这里的想法是,可以将三个业务规则实现为三个不同的元组约束(即表中的每一行都不是 false):
id
并且lang
必须相等(问一个问题,为什么不将其设为计算列?)。
如果letter
是,'E'
那么lang
必须是1
(我假设您说的问题中有错字'e'
而不是'E'
)。
如果letter
是,'F'
那么lang
必须是2
(我假设您说的问题中有错字2
而不是'F'
)。
约束对任何其他数据(例如 when letter
is 'X'
)“无话可说”,并将允许它通过。
所有三个元组约束都可以写成合取范式作为约束验证查询:
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 )
违反约束的数据可以简单地显示(在伪关系代数中)为:
T MINUS (constraint validation query)
在 SQL 中:
SELECT * FROM T
EXCEPT
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 )
最好能够重写谓词,以防一个人选择的查询像胶水一样运行在一个人选择的 DBMS 上!以上可以重写为例如
SELECT * FROM T
WHERE NOT ( id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 ) )
应用重写定律(德摩根和双重否定),例如
SELECT * FROM T
WHERE id <> lang
OR ( letter = 'E' AND lang <> 1 )
OR ( letter = 'F' AND lang <> 2 )
从逻辑上讲,这对优化器来说应该更好,因为要使上述矛盾成为矛盾,每个分离成员都必须为假(换句话说,只需一个 OR'ed 子句为真,数据就被认为是“坏的”) . 在实践中(理论上?),优化器无论如何都应该能够执行这样的重写!
ps null 不利于逻辑——避免使用它们!
这是我的带有示例数据的测试代码:
WITH Nums AS ( SELECT *
FROM ( VALUES (0), (1), (2) ) AS T (c) ),
Chars AS ( SELECT *
FROM ( VALUES ('E'), ('F'), ('X') ) AS T (c) ),
T AS ( SELECT N1.c AS id, N2.c AS lang,
C1.c AS letter
FROM Nums AS N1, Nums AS N2, Chars AS C1 )
SELECT * FROM T
EXCEPT
SELECT * FROM T
WHERE id = lang
AND ( letter <> 'E' OR lang = 1 )
AND ( letter <> 'F' OR lang = 2 );