CAS de la Clause sur la clause select jeter 'SQLCODE=-811, SQLSTATE=21000' Erreur
Cette requête est très bien de travailler dans Oracle. Mais il n'est pas de travail dans DB2. Il est en train de jeter
DB2 SQL Error: SQLCODE=-811, SQLSTATE=21000, SQLERRMC=null, PILOTE=3.61.65
erreur lorsque la sous-requête en vertu de l' THEN
clause est de retour en 2 lignes.
Cependant, ma question est: pourquoi serait-il exécuter, en premier lieu, comme mon QUAND clause s'avère être faux toujours.
SELECT
CASE
WHEN (SELECT COUNT(1)
FROM STOP ST,
FACILITY FAC
WHERE ST.FACILITY_ID = FAC.FACILITY_ID
AND FAC.IS_DOCK_SCHED_FAC=1
AND ST.SHIPMENT_ID = 2779) = 1
THEN
(SELECT ST.FACILITY_ALIAS_ID
FROM STOP ST,
FACILITY FAC
WHERE ST.FACILITY_ID = FAC.FACILITY_ID
AND FAC.IS_DOCK_SCHED_FAC=1
AND ST.SHIPMENT_ID = 2779
)
ELSE NULL
END STAPPFAC
FROM SHIPMENT SHIPMENT
WHERE SHIPMENT.SHIPMENT_ID IN (2779);
- La version de db2 utilisez-vous?
Vous devez vous connecter pour publier un commentaire.
Le standard SQL ne nécessite pas de couper court à l'évaluation (c'est à dire l'ordre d'évaluation des pièces de l'instruction de CAS). Oracle choisit de définir un raccourci de l'évaluation, cependant DB2 semble ne pas le faire.
La réécriture de votre requête un peu pour DB2 (8.1+ uniquement pour
FETCH
dans les sous-requêtes) devrait lui permettre d'exécuter (pas sûr si vous avez besoin de l'ajoutORDER BY
et n'ont pas de DB2 pour tester en ce moment)ORDER BY
n'est pas toujours nécessaire, il vous donne des résultats inattendus si vous ne parvenez pas à le préciser lors de l'instruction retourne plus d'une ligne. Donné il n'y a qu'une seule ligne (...à l'exception de quelques freak problème de concurrence, qui pourrait apporter d'autres problèmes pour cette version...), vous pouvez laisser leORDER BY
off. Bien sûr, étant donné que vous êtes de la commande par quelque chose assortie à une valeur (compte tenu de laWHERE
clause), la commande serait pas défini dans la présence de plusieurs lignes quelle que soit...Hmm... vous exécutez la même requête à deux reprises. J'ai le sentiment que vous n'êtes pas en pensant à jeux de (comment SQL fonctionne), mais en plus de procédure (c'est à dire, la façon dont la plupart des langages de programmation courants travail). Vous voulez probablement réécrire ce pour profiter de la façon dont Sgbdr sont censés travailler:
(pas de données de l'échantillon, donc pas testé. Il ya une couple d'autres façons d'écrire cette fonction sur d'autres besoins)
Cela doit fonctionner sur tous les Sgbdr.
Alors que ce passe ici, pourquoi ce travail? (Et pourquoi ai-je supprimer la référence à
Shipment
?)Tout d'abord, penchons-nous sur votre nouveau requête:
(Tout d'abord, arrêtez d'utiliser l'implicite-de la syntaxe de jointure - qui est, séparées par des virgules
FROM
clauses - toujours explicitement qualifier vos jointures. Pour une chose, c'est trop facile de rater une condition il faut joindre sur)...de ce fait, il est évident que votre déclaration est la même dans les deux requêtes, et montre de quoi tu es tente - si le jeu de données a une ligne, de le retourner, sinon, le résultat doit être null.
Entrez le
HAVING
clause:C'est essentiellement une
WHERE
clause pour les agrégats (fonctions commeMAX(...)
, ou ici,COUNT(...)
). Ceci est utile lorsque vous voulez vous assurer que certains aspects de la ensemble jeu correspond à un critère donné. Ici, nous voulons nous assurer qu'il y a seulement une ligne, l'utilisation d'unCOUNT(*) = 1
que la condition est approprié; si il n'y a plus (ou moins! pourrait être 0 lignes!) l'ensemble sera mis au rebut/ignorés.Bien sûr, à l'aide de
HAVING
signifie que nous sommes au moyen de l'ensemble, les règles habituelles s'appliquent: toutes les colonnes doivent être dans unGROUP BY
(qui est en fait une option dans ce cas), ou une fonction d'agrégation. Parce que nous ne voulons/s'attendre à une seule ligne, on peut tricher un peu, et il suffit de spécifier un simpleMAX(...)
pour satisfaire l'analyseur.À ce point, le nouveau sous-requête retourne une ligne (contenant une colonne) si il n'y avait qu'une seule ligne dans les données initiales, et pas de lignes autrement (cette partie est importante). Cependant, nous avons vraiment besoin de retourner une ligne indépendamment.
C'est une pratique table factice sur DB2 installations. Il a une ligne, avec une seule colonne contenant
'1'
(caractère '1', pas numérique 1). Nous sommes vraiment intéressés par le fait qu'il a une seule ligne...Un
LEFT JOIN
prend chaque ligne dans le jeu précédent (toutes les lignes jointes à partir du tableau précédent), et multiplie le résultat par chaque ligne de la table de référence, en multipliant par 1 dans le cas où le jeu sur la droite (la nouvelle référence, notre sous-requête) n'a pas de ligne. (Ce qui est différent de façon régulière(INNER) JOIN
œuvres, ce qui multiplie par 0 dans le cas où il n'y a pas de ligne) bien sûr, nous ne peut-être avoir 1 ligne, donc il n'y a qu'à aller pour avoir un maximum d'une ligne de résultat. Nous sommes tenus d'avoir uneON ...
clause, mais il n'y a pas de données pour réellement faire le lien entre les références, donc un simple toujours vrai condition est utilisé.Pour obtenir nos données, nous avons juste besoin d'obtenir de la colonne correspondante:
... si il y a une ligne de données, il est renvoyé. Dans le cas où il y a un autre nombre de lignes, le
HAVING
clause jette de l'ensemble, et de laLEFT JOIN
les causes de la colonne à être rempli avec unnull
(pas de données) de valeur.Pourquoi n'ai-je supprimer la référence à
Shipment
? Tout d'abord, vous n'étiez pas à l'aide de toutes les données de la table - la seule colonne dans le jeu de résultats a partir de la sous-requête. J'ai aussi de bonnes raisons de croire qu'il n'y aurait qu'une seule ligne retournée dans ce cas vous êtes à la spécification d'un seulshipment_id
valeur (ce qui implique que vous savez qu'il existe). Si nous n'avons pas besoin de quelque chose de la table (y compris le nombre de lignes dans la table), il est généralement préférable de le retirer de la déclaration: cela permet de simplifier le travail de la db doit faire.