约束相关表

时间:2019-05-29 03:17:50

标签: sql postgresql

我有2个表(ItemType和Item)。 ItemType具有布尔值hasSize,而Item表具有size列。

我想强制执行size仅在hasSize布尔值= true时设置。

我已经看到了讨论使用触发器进行验证的解决方案。但是,这不能提供与约束相同的鲁棒性。

这是非理想模式设计的问题,还是对此有合适的解决方案?

2 个答案:

答案 0 :(得分:3)

检查约束不能引用数据库中的其他表,并且触发器是围绕此限制的有效策略。我认为您的架构设计不是很糟糕。某些类型的项目相当大,并且这些信息属于item_type表中。

这是一个不使用触发器的替代解决方案,在这里我使用WITH CHECK OPTION修饰符对UPDATABLE VIEW施加了检查约束,以防止在基础表中修改数据。 请注意,这仅在通过视图插入或更新数据时才有效。您必须授予适当的权限,以便应用程序角色无法直接修改item表,但可以通过UPDATABLE VIEW

这是一个自包含脚本,其中包含示例数据和示例插入失败以及插入成功

-- set up dummy `item_type` table
CREATE TABLE item_type (
id int primary key generated by default as identity,
has_size bool,
name text not null unique
);
INSERT INTO item_type 
  (has_size, name) 
VALUES 
  (true, 'sizable type')
, (false, 'unisize');

-- set up dummy `item` table
CREATE TABLE item (
id int primary key generated by default as identity,
type_id int references item_type(id),
name text NOT NULL,
size text
);

INSERT INTO item
  (type_id, name, size)
VALUES
  (1, 'worlds best dad tee shirt', 'M')
, (2, 'usb key', NULL);

-- create updatable check view.
CREATE VIEW item_view AS
SELECT item.*
FROM item 
WHERE EXISTS (
SELECT 
FROM item_type 
WHERE item.type_id = item_type.id
  AND (item.size IS NOT NULL) = item_type.has_size
) 
WITH CASCADED CHECK OPTION; 
--    ^^^
-- i could have alternately used local 
-- instead of cascaded

此插入将失败

INSERT INTO item_view 
  (type_id, name, size) 
VALUES
  (2, 'dad socks', 'M');

它会产生以下错误:

ERROR:  new row violates check option for view "item_view"
DETAIL:  Failing row contains (3, 2, dad socks, M).

此插入将成功

INSERT INTO item_view 
  (type_id, name, size) 
VALUES
  (2, 'dad socks', NULL);

SELECT * FROM item按预期返回以下结果

 id | type_id |           name            | size
----+---------+---------------------------+------
  1 |       1 | worlds best dad tee shirt | M
  2 |       2 | usb key                   |
  4 |       2 | dad socks                 |

答案 1 :(得分:2)

是的,我将此称为设计问题。通常,可以通过 not 存储hassize来避免此类问题,因为可以在查询数据库时派生它。

有时必须存储冗余数据以提高性能,但随后您必须付出可能担心的潜在不一致的代价。

如果您无法避免持续使用hassize,那么使用触发器通常是最好的解决方案。尝试通过减少并发(例如锁或可序列化的隔离)来避免异常。