2011-02-06 12 views
4

afin de faire le type d'affirmation suivanteEst-ce la manière correcte de créer une assertion SQL?

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

est ce droit d'affirmation?

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

La deuxième contrainte ne fonctionne-t-elle pas? Ou demandez-vous s'il y a un meilleur moyen? –

+0

Je demande si c'est la bonne ou pas – user591931

Répondre

8

Pour plus de détails sur CREATE ASSERTION voir la spécification ISO standard SQL-92. La définition de CHECK devrait être entre parenthèses.

CURRENT_DATE n'a pas de parenthèses.

USER et DATE sont des mots réservés.

Les instructions SQL doivent être terminées par un point-virgule.

Les mots-clés SQL doivent être en majuscules.

Essayez quelque chose comme ceci:

CREATE ASSERTION assert 
CHECK (0 = (
      SELECT COUNT(*) 
       FROM Video 
      WHERE my_date = CURRENT_DATE 
      GROUP 
       BY my_user 
      HAVING COUNT(*) >= 10 
      )); 

Vous pouvez tester que la syntaxe est correcte à l'aide du Mimer en ligne SQL-92 Validator. Cependant, vous devriez également tester votre logique, par ex. CURRENT_DATE est non déterministe.

En outre, je ne pense pas que ASSERTION mordra jamais. Lorsque la cardinalité de la sous-requête est inférieure à 10, elle renvoie zéro ligne et 0 = empty set est évaluée à UNKNOWN. Lorsque la cardinalité de la sous-requête est égale ou supérieure à 10, la condition de recherche évalue TRUE. SQL-92 états standard

L'affirmation n'est pas satisfaite si et que si le résultat de l'évaluation de la condition de recherche est fausse.

Notez que vous pouvez remplacer votre CHECK (0 = (SELECT COUNT(*) FROM...)) construction avec CHECK (NOT EXISTS (SELECT * FROM...)), ce dernier dont je trouve plus facile à écrire.


MISE À JOUR:

Comment dois-je écrire l'affirmation à l'aide CHÈQUE EXISTE PAS?

Comme je l'ai dit ci-dessus, votre logique semble erronée de sorte qu'il est difficile de mettre en œuvre correctement;)

Disons que la règle est de limiter les vidéos à 10 par utilisateur et par jour.Parce que cela implique seulement une seule table, il serait plus approprié d'utiliser une contrainte CHECK au niveau de la table; une telle contrainte est vérifiée quand la table est mise à jour ce qui est suffisant dans ce cas (il n'y a pas de raison pour que cela ne soit pas un ASSERTION, qui peut être vérifié en théorie chaque fois que une table dans le schéma est mise à jour):

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 
         )); 

MISE à JOUR 2:

merci, maintenant, disons que nous voulons limiter vidéos à 100 par utilisateur et par an, dans ce cas en utilisant current_date serait nécessaire ne serait-il pas?

réexaminera qu'un CHECK/ASSERTION ne sera vérifié lorsque les données dans le tableau/schéma est mis à jour. Le problème avec l'utilisation de CURRENT_DATE (et d'autres fonctions non déterministes) dans une contrainte est que la règle métier peut être invalidée simplement par l'horloge qui passe d'une période à l'autre mais si les données n'ont pas été changées dans cette période l'échec de l'intégrité des données ne sera pas détecté et la base de données contiendra des données non valides.

Une autre considération est ce que l'on entend par une année en contexte. Il peut s'agir de l'année calendaire (du 1er janvier au 31 décembre inclusivement) ou d'autres dates fixes définies par l'entreprise (par exemple du 1er avril au 31 mars inclus), auquel cas le regroupement par année et par utilisateur est trivial.

Un cas plus intéressant est lorsque la règle limite le décompte pour période de 12 mois; l'étendre à la fois au passé et au futur évite la question «non déterministe» ci-dessus. Considérons un standard approach of using an auxiliary calendar table, contenant une ligne pour chaque jour applicable à l'entreprise, étendu dans le passé et à l'avenir seulement pour autant que nécessaire ne devrait toujours comprendre que quelques milliers de lignes. Chaque ligne aurait la date comme une clé avec une deuxième colonne pour cette date plus un an (et si nécessaire, vous pourriez affiner la définition de 'une année' à une granularité d'un jour!) Le test pour impliquerait de rejoindre le calendrier tableau, regroupant sur la date du calendrier et l'utilisateur et en comptant par exemple quelque chose comme ceci:

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; 

Cela pourrait être mis dans une contrainte CHECK (NOT EXISTS (.... Cela pourrait toujours être une contrainte au niveau de la table: car la table Calendar est une table auxiliaire, elle ne serait sujette qu'à des mises à jour contrôlées peu fréquentes (mais peut également être un ASSERTION si nécessaire).

+0

Comment dois-je écrire l'assertion en utilisant CHECK NOT EXISTS? – user591931

+0

merci, maintenant disons que nous voulons limiter les vidéos à 100 par utilisateur par an, dans ce cas en utilisant current_date serait nécessaire ne serait-il pas? Merci pour votre temps – user591931

+0

merci beaucoup – user591931

Questions connexes