詳細についてCREATE ASSERTION
は、ISO SQL-92 標準仕様を参照してください。
定義はCHECK
括弧で囲む必要があります。
CURRENT_DATE
には括弧がありません。
USER
およびDATE
は予約語です。
SQL ステートメントは、セミコロン文字で終了する必要があります。
SQL キーワードは大文字にする必要があります。
このようなことをもっと試してください:
CREATE ASSERTION assert
CHECK (0 = (
SELECT COUNT(*)
FROM Video
WHERE my_date = CURRENT_DATE
GROUP
BY my_user
HAVING COUNT(*) >= 10
));
オンラインの Mimer SQL-92 Validatorを使用して、構文が正しいことをテストできます。ただし、ロジックもテストする必要があります。たとえばCURRENT_DATE
、非決定論的です。
ASSERTION
また、これは決して噛むことはないと思います。サブクエリのカーディナリティが 10 未満の場合、ゼロ行が返され、0 = empty set
と評価されUNKNOWN
ます。サブクエリのカーディナリティが 10 以上の場合、検索条件は評価されTRUE
ます。SQL-92 標準状態
検索条件の評価結果が false である場合にのみ、アサーションは満たされません。
CHECK (0 = (SELECT COUNT(*) FROM...))
コンストラクトをに置き換えることができることに注意してください。CHECK (NOT EXISTS (SELECT * FROM...))
後者の方が書きやすいと思います。
アップデート:
CHECK NOT EXISTS を使用してアサーションをどのように記述すればよいですか?
上で述べたように、ロジックに欠陥があるように見えるため、適切に実装するのは困難です ;)
ビデオをユーザーごとに 1 日 10 に制限するというルールがあるとします。これには 1 つのテーブルしか含まれないため、テーブル レベルのCHECK
制約を使用する方が適切です。このような制約は、テーブルが更新されるときにチェックされますが、この場合はこれで十分です (ただし、スキーマ内のテーブルが更新されるASSERTION
たびに理論的にチェックできる にできない理由はありません):
ALTER TABLE Video ADD
CONSTRAINT video_limit_10_per_user_per_day
CHECK (NOT EXISTS (
SELECT v1.my_user, v1.my_date
FROM Video AS V1
GROUP BY v1.my_user, v1.my_date
HAVING COUNT(*) > 10
));
更新 2:
ありがとう、では、ユーザーごとに年間 100 本の動画に制限したいとしましょう。この場合、current_date を使用する必要がありますね。
CHECK
/ASSERTION
は、テーブル/スキーマのデータが更新されたときにのみチェックされることを再度考慮してください。制約で (およびその他の非決定論的関数)を使用する場合の問題CURRENT_DATE
は、ある期間から次の期間にクロックが刻々と過ぎていくだけでビジネス ルールが無効になる可能性があることですが、その期間にデータが変更されていない場合は、データ整合性の障害は検出されず、データベースには無効なデータが含まれます。
もう 1 つの考慮事項は、文脈上、1 年が何を意味するかです。
暦年 (1 月 1 日から 12 月 31 日まで) または企業によって定義されたその他の固定日 (たとえば、4 月 1 日から 3 月 31 日まで) である可能性があります。
より興味深いケースは、ルールが任意の12 か月の期間の集計を制限する場合です。これを過去と未来の両方に拡張すると、上記の「非決定論的」問題を回避できます。
補助カレンダー テーブルを使用する標準的なアプローチを検討してください。このテーブルには、企業に適用可能な毎日の行が 1 つ含まれ、必要な範囲だけ過去と未来に拡張されますが、それでも数千行で構成される必要があります。各行は、その日付に 1 年を加えた 2 番目の列を持つキーとして日付を持ちます (必要に応じて、「1 年」の定義を 1 日単位で微調整できます!) のテストには、カレンダーへの参加が含まれます。テーブル、カレンダーの日付とユーザーでグループ化し、たとえば次のようにカウントします。
SELECT C1.dt, V1.my_user
FROM Video AS V1
INNER JOIN Calendar AS C1
ON (V1.my_date BETWEEN C1.dt AND C1.dt_plus_one_year)
GROUP
BY C1.dt, V1.my_user
HAVING COUNT(*) > 100;
CHECK (NOT EXISTS (...
これは、制約に入れることができます。これはまだテーブル レベルのCHECK
制約である可能性があります。Calendar テーブルは補助テーブルであるため、制御された更新が頻繁に行われることはありません (ただし、ASSERTION
必要に応じて変更される可能性があります)。