PostgreSQL中的JSON外键

PostgreSQL中的JSON外键,postgresql,Postgresql,是否可以在PostgreSQL中为json属性分配外键?下面是我想要实现的一个示例,但它不起作用: CREATE TABLE Users (Id int NOT NULL PRIMARY KEY); CREATE TABLE Data ( Id int NOT NULL PRIMARY KEY, JsonData json NOT NULL, -- [{Id: 1, somedata: null},{Id: 2, somedata: null}, ...] CONSTR

是否可以在PostgreSQL中为json属性分配外键?下面是我想要实现的一个示例,但它不起作用:

CREATE TABLE Users (Id int NOT NULL PRIMARY KEY);

CREATE TABLE Data (
    Id int NOT NULL PRIMARY KEY,
    JsonData json NOT NULL, -- [{Id: 1, somedata: null},{Id: 2, somedata: null}, ...]
    CONSTRAINT FK_Users_Data FOREIGN KEY (JsonData->Id) REFERENCES Users(Id) -- this constraint will fail
);

外键参数必须是列名:

你必须正常化

create table user_data (
    id int not null primary key,
    user_id int not null,
    somedata text,
    constraint fk_users_data foreign key (user_id) references Users(Id)
);

为json属性分配外键是不可能的,也可能永远不可能。这将是对PostgreSQL外键执行的一个重大且相当复杂的改变。我不认为这是不可能做到的,但将面临与外键阵列补丁类似的问题


使用9.4,可以将整个json对象作为外键,因为
jsonb
支持相等测试。在9.3中,您甚至不能这样做。

这里有一个小小的SPI函数,我使用它来对与jsonb列的一对多关系进行完整性约束

CREATE TABLE foo (
  id INTEGER NOT NULL
)

CREATE TABLE bar (
  foo_ids pg_catalog.jsonb DEFAULT '[]'::jsonb NOT NULL,
  CONSTRAINT bar_fooids_chk CHECK (have_ids ('foo', foo_ids))
)

使用
foo
上的两个触发器,它几乎与外键一样好。

不,这是不可能的。为什么不从json中获取id并在表中用作FK…@cracker:这只是一个示例;在我的项目中,我在json字段中有一个项目数组-如果没有这样的约束,它将需要创建一个新表…如果没有表,那么如何给出外键?您可以创建一个触发器,在列发生更改时从json中提取id值,然后将其放入一个可用于定义外键。如今(2015年),有了稳定的pg9.4+版本及其社区,有一些“良好实践”或通常的pg社区惯例来表示外键(正式或非正式pg分配)?请参见参考“JSON链接约定”。。。例如,这里@ArtemGr show alternative,表示一行中的ID,我喜欢,但它在pg社区中使用?@PeterKrauss不,不是真的。这种情况并没有明显改变,就像数组字段的外键一样。即使有人想要实现它,也有一些难以处理的性能问题,到目前为止还没有人这样做。您是否有一个基准测试来显示您的
have_id()
函数的性能(理想情况下是与它在SQL中的模拟值相比较)?即使是“糟糕的性能”,如果它是通用的和稳定的,对PostgreSQL社区来说也是一个很好的建议。不,我还没有对它进行基准测试,但性能特征对我来说似乎非常透明。该函数在JSONB数组上循环,并从查询中为每个ID执行一个
SELECT COUNT(*)。它的速度与这些查询的总和一样快。函数本身的性能成本应该是可忽略的。我没有SQL版本,也不知道如何编写。我认为PosgreSQL最终将拥有对基于数组的外键()的一流支持,因此从长远来看不需要这种解决方法。@ArtemGr我知道它很旧,但您可能可以使用
COUNT(1)
而不是
COUNT(*)来提高该循环的性能
@SampsonCrowley我已经有一段时间没有测试过了,但是IIRC的
COUNT(*)
被PostgreSQL优化了(例如,星星没有扩展到任何字段),我倾向于保持
COUNT(*)
的可读性(POLA)。@ArtemGr啊,那么我已经过时了;我总是
COUNT(1)
,因为它(对我来说)具有相同的可读性,而且我总是听说它比计算列更有效