强制在计算列之前评估检查约束

Force check constraints to be evaluated before computed columns

我想在 table 中有一个 JSON 列。我想要(持久化)计算列从 JSON 数据中提取有用的信息。 我想要一个“严格的”JSON 路径,但我也想检查 JSON 中是否存在该路径,以便错误消息特定于 table 而不仅仅是关于非法 JSON 路径。

CREATE TABLE DataWithJSON (
  DataID BIGINT,
  DataJSON NVARCHAR(MAX) CONSTRAINT CK_DataWithJSON_DataJSON CHECK (
    ISJSON(DataJSON) = 1
    AND JSON_VALUE(DataJSON, 'lax $.Data.ID') IS NOT NULL
  ),
  DataJSONID AS JSON_VALUE(DataJSON, 'strict $.Data.ID') PERSISTED
);

INSERT INTO DataWithJSON (DataID, DataJSON)
  VALUES (666, N'{"Data":{"Name":"Tydýt"}}');

这段代码returns(在我的机器上)有点神秘的错误信息

Msg 13608, Level 16, State 2, Line xx Property cannot be found on the specified JSON path.

我希望看到更具体的信息

Msg 547, Level 16, State 0, Line yy The INSERT statement conflicted with the CHECK constraint "CK_DataWithJSON_DataJSON". The conflict occurred in database "DB", table "schema.DataWithJSON", column 'DataJSON'.

这是否可以仅通过 table 约束来实现,还是我运气不好,我是否必须在插入到 [= 之前​​检查存储的 procedure/application 中的 JSON 36=]?

一个 解决方案是在计算列中使用“松散”路径,希望这不是唯一 解决方案。如果还有 none 其他要找到的解决方案,我会回到那个解决方案。

您无法控制检查约束和计算列的计算顺序,但您可以在计算列定义中使用 CASE 表达式,这样 JSON_VALUE(... 'strict ...) 部分仅在检查约束将通过。

CREATE TABLE DataWithJSON (
  DataID BIGINT,
  DataJSON NVARCHAR(MAX) CONSTRAINT CK_DataWithJSON_DataJSON CHECK (
    ISJSON(DataJSON) = 1 AND JSON_VALUE(DataJSON, 'lax $.Data.ID') IS NOT NULL
  ),
  DataJSONID AS CASE WHEN ISJSON(DataJSON) = 1 AND JSON_VALUE(DataJSON, 'lax $.Data.ID')  IS NOT NULL THEN JSON_VALUE(DataJSON, 'strict $.Data.ID') END PERSISTED
);

Msg 547, Level 16, State 0, Line 9 The INSERT statement conflicted with the CHECK constraint "CK_DataWithJSON_DataJSON". The conflict occurred in database "Foo", table "dbo.DataWithJSON", column 'DataJSON'. The statement has been terminated.