In ,Joe Celko 提供了 Series 表(其他地方称为 Tally 或 Numbers)的 ANSI SQL 定义。他的定义确保列中的值是唯一的、正数且从 1 到最大值连续:
CREATE TABLE Series (
seq INTEGER NOT NULL PRIMARY KEY,
CONSTRAINT non_negative_nbr CHECK (seq > 0),
CONSTRAINT numbers_are_complete CHECK ((SELECT COUNT(*) FROM Series) = (SELECT MAX(seq) FROM Series))
);
PRIMARY KEY 声明确保唯一性。积极性由约束保证non_negative_nbr
。有了这两个约束,约束就保证了连续性numbers_are_complete
.
SQL Server 不支持检查约束中的子查询。当我尝试创建系列表时,我收到如下错误:
Msg 1046, Level 15, State 1, Line 4
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Msg 102, Level 15, State 1, Line 4
Incorrect syntax near ')'.
如果我删除不支持的约束numbers_are_complete
,我留下这个定义:
CREATE TABLE Series (
seq INTEGER NOT NULL PRIMARY KEY,
CONSTRAINT non_negative_nbr CHECK (seq > 0)
);
当我尝试创建此版本的系列时,它成功了:
Command(s) completed successfully.
此版本的 Series 较弱,因为它不强制表中数字的连续性。
为了演示这一点,首先我必须填充表。我采用了 Itzik Ben-Gan 在他的文章中描述的技术“虚拟辅助数字表 http://www.sqlmag.com/article/sql-server/virtual-auxiliary-table-of-numbers' 对 65,536 行有效地执行此操作:
WITH
N0(_) AS (SELECT NULL UNION ALL SELECT NULL),
N1(_) AS (SELECT NULL FROM N0 AS L CROSS JOIN N0 AS R),
N2(_) AS (SELECT NULL FROM N1 AS L CROSS JOIN N1 AS R),
N3(_) AS (SELECT NULL FROM N2 AS L CROSS JOIN N2 AS R),
N4(_) AS (SELECT NULL FROM N3 AS L CROSS JOIN N3 AS R)
INSERT INTO Series (
seq
)
SELECT
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n
FROM N4;
该查询产生如下输出:
(65536 row(s) affected)
现在我可以从这样的表中进行选择以生成 65,536 行:
SELECT seq
FROM Series;
我已经截断了结果集,但它看起来像这样:
seq
1
2
...
65535
65536
自己检查一下,你会发现区间 [1, 65536] 中的每个数字都在结果集中。该系列是连续的。
但我可以通过删除不是范围端点的任何行来打破连续性:
DELETE FROM Series
WHERE seq = 25788;
如果强制执行连续性,此语句将引发错误,但它会成功:
(1 row(s) affected)
人类很难通过目视检查找到缺失的值。在遇到麻烦之前,他们必须首先怀疑某个值丢失了。由于这些原因,篡改 Series 数据是一种向依赖 Series 表连续的 SQL Server 应用程序引入细微错误的简单方法。
假设用户编写了一个从 Sequence 读取的查询,以枚举来自另一个源的行。经过我的篡改,该查询现在会在某个值附近产生不正确的结果 - 到第 25,788 行时,所有内容都减少了 1。
可以编写一个查询来检测 Series 表中的缺失值,但如何限制该表以使缺失值成为不可能?