PostgreSQL中的JSON外键

use*_*797 15 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}, ...]
    CONSTRAINT FK_Users_Data FOREIGN KEY (JsonData->Id) REFERENCES Users(Id) -- this constraint will fail
);
Run Code Online (Sandbox Code Playgroud)

Cra*_*ger 14

将外键分配给json属性是不可能的,也可能是不可能的.对PostgreSQL的外键实施来说,这是一个重大且相当复杂的变化.我不认为这是不可能的,但是会遇到与外键到阵列补丁所遇到的问题类似的问题.

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


Luk*_*uke 7

是的,这是可能的,但您必须存储另一个值。如果您将架构更改为:

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

CREATE TABLE Data (
    Id int NOT NULL PRIMARY KEY,
    JsonData json NOT NULL,
    UserId int generated always as ((JsonData->>'Id')::int) stored references Users(Id)
);

INSERT INTO Users VALUES (1);
Run Code Online (Sandbox Code Playgroud)

不存在的外键:

INSERT INTO Data VALUES (1, '{"Id": 3}');
Run Code Online (Sandbox Code Playgroud)

返回错误:

ERROR: insert or update on table "data" violates foreign key constraint "data_userid_fkey" DETAIL: Key (userid)=(3) is not present in table "users".

有效的外键:

INSERT INTO Data VALUES (1, '{"Id": 1}');
Run Code Online (Sandbox Code Playgroud)


Art*_*mGr 6

这是一个小函数have_ids,我用它来与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))
)
Run Code Online (Sandbox Code Playgroud)

有几个触发器foo几乎和外键一样好.

  • 不,我还没有进行基准测试,但是性能特征对我来说似乎非常透明。该函数遍历JSONB数组,并对每个ID执行一次“ SELECT COUNT(*)FROM”查询。它和这些查询的总和一样快。函数本身的性能成本应该忽略不计。我没有SQL版本,也不知道如何编写。我认为PosgreSQL最终将对基于数组的外键(https://wiki.postgresql.org/wiki/Todo#Referential_Integrity)提供一流的支持,因此从长远来看不需要这种解决方法。 (2认同)