7

次のタイプのアサーションを作成するために

create assertion assert  
check "EMPTY SET" = (select User         
     from Video  
     where date=current_date()  
     group by user  
having count(*) >= 10

この主張は正しいですか?

create assertion assert  
check  0 = (select count(*)  
     from Video  
     where date=current_date()  
     group by user  
having count(*) >= 10
4

1 に答える 1

14

詳細について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必要に応じて変更される可能性があります)。

于 2011-02-07T11:52:23.397 に答える