如何在数据库中存储点 (x, y)?
How to store point (x, y) in a database?
我需要在我的数据库中存储位置(x,y 点),其中点可以为空并且 X
和 Y
总是小于 999。目前我正在使用EFCore Code First 和 Postgresql 数据库,但我想灵活一点,这样我就可以切换到 MSSql 而无需太多工作。我不打算离开 EF Core。
现在,我有两列:LocationX
和 LocationY
,都是 int?
类型。我不确定这是否是好的解决方案,因为技术上 DB 允许(X=2,Y=null),而且它应该是。它要么都为空,要么都不是。
我的选项二是将其存储在一个字符串列中:"123x321",最大长度为 7。
有没有更好的方法?
谢谢,
检查约束可用于强制两列同时为 NULL 或 NOT NULL:
CREATE TABLE t(id INT,
x INT,
y INT,
CHECK((x IS NULL AND y IS NULL) OR (x IS NOT NULL AND y IS NOT NULL))
);
除了@LukaszSzozda 建议的检查约束之外,您还可以通过对每个值附加检查约束来限制 x、y 值。所以假设它们也必须在 0,999 范围内然后
CREATE TABLE t(id INT,
x INT constraint x_range check ( x>=0 and x<=999),
y INT constraint y_range check ( y>=0 and y<=999),
CHECK((x IS NULL AND y IS NULL) OR (x IS NOT NULL AND y IS NOT NULL))
);
就您存储单个字符串的想法而言 - 非常糟糕。您不仅会在每次需要时遇到分隔值的问题,而且还允许明显无效的数据。就数据库而言,值“1234567”甚至 'abcdefg' 都是完全有效的。
因此,您的 table 定义必须考虑并消除它们。这样你的 table 定义就变成了:
create table txy
( xy_string varchar(7)
, constraint xy_format check( xy_string ~* '^\d{1,3}x\d{1,3}')
)
insert into txy(xy_string)
( values ('1x2'), ('354X512'), ('38x92') );
这实际上是一种缩减,因为它回到了单一约束,但您的查询现在需要如下内容:
select xy_string
, regexp_replace(xy_string, '^(\d+)(X|x)(\d+)','') x
, regexp_replace(xy_string, '^(\d+)(X|x)(\d+)','') y
from txy;
请参阅此处 demo。
简而言之,永远不要将数字值组存储为单个分隔字符串。额外的工作是不值得的。
我需要在我的数据库中存储位置(x,y 点),其中点可以为空并且 X
和 Y
总是小于 999。目前我正在使用EFCore Code First 和 Postgresql 数据库,但我想灵活一点,这样我就可以切换到 MSSql 而无需太多工作。我不打算离开 EF Core。
现在,我有两列:LocationX
和 LocationY
,都是 int?
类型。我不确定这是否是好的解决方案,因为技术上 DB 允许(X=2,Y=null),而且它应该是。它要么都为空,要么都不是。
我的选项二是将其存储在一个字符串列中:"123x321",最大长度为 7。
有没有更好的方法?
谢谢,
检查约束可用于强制两列同时为 NULL 或 NOT NULL:
CREATE TABLE t(id INT,
x INT,
y INT,
CHECK((x IS NULL AND y IS NULL) OR (x IS NOT NULL AND y IS NOT NULL))
);
除了@LukaszSzozda 建议的检查约束之外,您还可以通过对每个值附加检查约束来限制 x、y 值。所以假设它们也必须在 0,999 范围内然后
CREATE TABLE t(id INT,
x INT constraint x_range check ( x>=0 and x<=999),
y INT constraint y_range check ( y>=0 and y<=999),
CHECK((x IS NULL AND y IS NULL) OR (x IS NOT NULL AND y IS NOT NULL))
);
就您存储单个字符串的想法而言 - 非常糟糕。您不仅会在每次需要时遇到分隔值的问题,而且还允许明显无效的数据。就数据库而言,值“1234567”甚至 'abcdefg' 都是完全有效的。 因此,您的 table 定义必须考虑并消除它们。这样你的 table 定义就变成了:
create table txy
( xy_string varchar(7)
, constraint xy_format check( xy_string ~* '^\d{1,3}x\d{1,3}')
)
insert into txy(xy_string)
( values ('1x2'), ('354X512'), ('38x92') );
这实际上是一种缩减,因为它回到了单一约束,但您的查询现在需要如下内容:
select xy_string
, regexp_replace(xy_string, '^(\d+)(X|x)(\d+)','') x
, regexp_replace(xy_string, '^(\d+)(X|x)(\d+)','') y
from txy;
请参阅此处 demo。
简而言之,永远不要将数字值组存储为单个分隔字符串。额外的工作是不值得的。