SQL For Smartiesで、JoeCelkoはSeriesテーブルのANSISQL定義を提供します(他の場所ではTallyまたはNumbersと呼ばれます)。彼の定義は、列の値が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))
);
一意性は、PRIMARYKEY宣言によって保証されます。陽性は制約によって保証されますnon_negative_nbr
。これらの2つの制約が設定されている場合、隣接性は制約によって保証されますnumbers_are_complete
。
SQL Serverは、チェック制約のサブクエリをサポートしていません。Seriesテーブルを作成しようとすると、次のようなエラーが発生します。
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.
このバージョンのシリーズは、テーブル内の数値の連続性を強制しないため、脆弱です。
これを示すために、最初にテーブルにデータを入力する必要があります。ItzikBen-Ganが彼の記事「VirtualAuxiliaryTableof 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テーブルに依存するSQLServerアプリケーションに微妙なバグを導入する簡単な方法です。
ユーザーがSequenceから読み取り、別のソースからの行を列挙するクエリを作成したと想定します。私が改ざんした後、そのクエリは特定の値の周りに誤った結果を生成するようになりました-25,788行目までに、すべてが1つずれています。
Seriesテーブルで欠落している値を検出するクエリを作成することは可能ですが、欠落している値が不可能になるようにテーブルを制約するにはどうすればよいですか?