J'essaie d'écrire une requête dans Oracle SQL qui prend deux paramètres et trouve dans la table toutes les instances où seulement ou se produisent, quel que soit le nombre d'entre eux dans la recherche. Voici un exemple de ce que je recherche:
SELECT DISTINCT ID, FileType, COUNT(FileType) FROM Table ta WHERE (ta.FileType = 'jpg' or ta.FileType = 'png') and NOT EXISTS (SELECT * FROM Table tb WHERE ta.FileType = tb.FileType and (tb.FileType != 'jpg' or tb.FileType != 'png')) GROUP BY ID, FileType;
Mon objectif est de prendre tous les ID avec UNIQUEMENT les png OU les jpg et d'omettre le reste, donc je veux seulement les ID 2, 3 et 4 pour être renvoyé.
J'ai essayé de rechercher des solutions ici et je n'ai rien trouvé qui semble correspondre à mon cas. (La plus proche étant cette question: SQL sélectionne les lignes avec seulement un une certaine valeur en eux )
J'ai réussi à découvrir que le problème peut être résolu par la division relationnelle, mais je n'en ai pas eu jusqu'ici. Jusqu'à présent, ma requête ressemble à ceci:
| ID | FileType | COUNT(FileType) | |-----|----------|-----------------| | 1 | txt | 1 | | 1 | png | 3 | | 1 | jpg | 2 | ==================================== | 2 | txt | 0 | | 2 | png | 6 | | 2 | jpg | 0 | ==================================== | 3 | txt | 0 | | 3 | png | 0 | | 3 | jpg | 5 | ==================================== | 4 | txt | 0 | | 4 | png | 3 | | 4 | jpg | 1 | ==================================== | 5 | txt | 5 | | 5 | png | 0 | | 5 | jpg | 3 |
Quand j'essaye ceci, je n'obtiens aucun résultat. Quelqu'un a des idées sur lesquelles je me suis trompé?
3 Réponses :
Vous êtes proche. Voyez simplement combien de types de fichiers distincts vous avez. Voici vos identifiants:
SELECT ID FROM Table ta GROUP BY ID HAVING count(distinct FileType) <= 2 and max(ta.FileType) in ('jpg','png') and min(ta.FileType) in ('jpg','png');
Mise à jour: la partie supérieure échouera pour le cas 4.
Cela le fera mais c'est moche:
SELECT ID FROM Table ta GROUP BY ID HAVING count(distinct FileType) = 1 and max(ta.FileType) in ('jpg','png');
C'est moche car vous ne pouvez pas l'étendre pour 3 valeurs.
Vous pouvez utiliser les opérateurs set:
SELECT ID FROM tab WHERE FileType IN ('jpg', 'png') MINUS SELECT ID FROM (SELECT * FROM tab WHERE FileType IS NOT NULL) WHERE FileType NOT IN ('jpg', 'png')
Hypothèse: FileType n'est pas nullable.
Gestion NULL:
SELECT ID FROM tab WHERE FileType IN ('jpg', 'png') MINUS SELECT ID FROM tab WHERE FileType NOT IN ('jpg', 'png')
C'est une bonne et belle requête. Vous pouvez l'améliorer en l'écrivant de cette manière: SELECT ID FROM onglet WHERE FileType IN ('jpg', 'png') moins SELECT ID FROM onglet WHERE FileType NOT IN ('jpg', 'png') code>
Cette réponse exprime au mieux la demande. SQL pur et puissant.
Merci, c'est la solution la plus claire et la plus simple à comprendre. Je crois que cela fonctionnera.
Mes excuses pour avoir nécrosé si rapidement et pour ne pas m'en être rendu compte plus tôt, mais si le FileType est Nullable, la sagesse conventionnelle me dit que remplacer IN par '= (jpg ou png)' et NOT IN par '! = (Jpg ou png)' serait correct, mais cela ne semble pas être le cas. Des idées dans cette situation?
Les valeurs @Cody Null peuvent être supprimées à l'aide de la vue intégrée.
Merci pour votre aide!
Il suffit d'utiliser une table "d'aide":
WITH TypeCounts AS ( SELECT ID, FileType, COUNT(*) AS CNT FROM Table GROUP BY ID, FileType ) SELECT * FROM Table LEFT JOIN TypeCounts txt ON txt.ID = Table.ID AND txt.FileType = 'txt' LEFT JOIN TypeCounts jpg ON jpg.ID = Table.ID AND jpg.FileType = 'jpg' LEFT JOIN TypeCounts png ON png.ID = Table.ID AND png.FileType = 'png' WHERE COALESCE(txt.CNT,0) = 0 AND ( COALESCE(jpg.CNT,0) > 0 OR COALESCE(png.CNT,0) > 0)
Ce qui est bien avec cette solution, c'est qu'elle est très claire en ce qui concerne les règles métier et est donc plus facile à maintenir.