如何在数据库中存储点 (x, y)?

How to store point (x, y) in a database?

我需要在我的数据库中存储位置(x,y 点),其中点可以为空并且 XY 总是小于 999。目前我正在使用EFCore Code First 和 Postgresql 数据库,但我想灵活一点,这样我就可以切换到 MSSql 而无需太多工作。我不打算离开 EF Core。

现在,我有两列:LocationXLocationY,都是 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))
);

db<>fiddle demo

除了@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

简而言之,永远不要将数字值组存储为单个分隔字符串。额外的工作是不值得的。