9
votes

Quelle est la meilleure façon d'utiliser la jointure extérieure gauche pour vérifier la non-existence de lignes connexes

Utilisation de MySQL 5.x Je veux efficacement Sélectionnez toutes les lignes de la table x où il y a aucune ligne associée dans le tableau Y satisfaisant une condition, par exemple

donner moi tous les enregistrements en x où un y a associé avec foo = bar n'existe pas xxx

si je comprends, une jointure extérieure gauche est garantie pour produire une rangée pour chaque rangée La table gauche (premier) - x dans ce cas - une ligne satisfaisante ou non dans la table jointe a été trouvée. Ce que je veux faire, c'est alors sélectionner uniquement les lignes où aucune ligne n'a été trouvée.

Il me semble que Y.X_ID devrait être null s'il n'y a pas d'enregistrement correspondant, mais ce test ne semble pas travail. Y.x_id = 0 ou! Y.x_id.

EDITS : erreur de transcription corrigée (sur non aussi) qui a été signalé par plusieurs réponses. Erreur grammaticale fixe.


0 commentaires

4 Réponses :


22
votes
LEFT OUTER JOIN Y AS
-- should be
LEFT OUTER JOIN Y ON
-- This however is allowed
LEFT OUTER JOIN table2 as Y ON ....

1 commentaires

Merci. Comme je le mentionne dans mon édition, le tel était un glissement. (La requête réelle est bien sûr un désordre horrible alors j'essayais de simplifier.)



4
votes

Vérification Si la clé primaire du tableau Y est NULL ferait l'affaire, qui indique à la jointure ne correspondait pas à:

SELECT count(id) FROM X 
LEFT OUTER JOIN Y ON (y.X_id = X.id AND y.foo = 'bar')
WHERE y.Y_id is null


2 commentaires

@podperson: C'est une erreur très courante. La logique ternaire utilisée par SQL est confuse parfois même d'avoir des développeurs SQL expérimentés.


Vous pouvez faire <=> null dans mysql :-)



-1
votes

Pourquoi utiliser une jointure extérieure? Ne pouviez-vous pas faire:

SELECT count(id) 
FROM X JOIN Y AS y.X_id = X.id AND y.foo <> 'bar'


4 commentaires

Cela sélectionnerait des correspondances, op est à la recherche de "No Match"


Cela lui donnerait toutes les lignes de X où il y a une ligne assortie dans Y qui n'a pas y.foo = bar (remarquez le <>). J'ai probablement mal compris la question ...


Un joint interne peut jamais donner des lignes non amorties, il va simplement masquer ces lignes de la vue, c'est le problème. Remarquez comment la jointure externe teste pour les deux y.x_id = x.id et y.foo = 'bar' , exactement opposé pour ce serait y.x_id <> x.id ou Y.FOO <> 'BAR' , mais cela entraînera un résultat différent, avec de nombreuses lignes y correspondantes par X-Row.


J'ai mal compris la question .. mon mauvais.



2
votes

La réponse de Johan est correcte à 100%.

En plus de cela, il y a aussi cette option: xxx

en fonction de la taille de votre table et de votre distribution de données, cela peut être plus efficace. Testez et gardez les deux sens pour une référence future.


10 commentaires

Pouvez-vous élaborer lorsqu'il n'existe pas est plus efficace? Peut-être que lorsque la table X est grande et que la table Y est assez petite? Juste curieux, merci.


Le Gauche Join / Not Null Solution et le n'existe pas On peut entraîner différents plans du planificateur d'exécution. Ceci (peut) dépendre de nombreux facteurs, tels que le système DB que vous utilisez (mySQL ou SQL-Server ou autre), la version du système, le moteur en question (innoDB ou Myisam), la taille des tables, la distribution des champs joints (comme le pourcentage de x.id qui existe réellement sur y ), s'il y a null s dans les champs ou non , etc. Donc, j'ai une démonstration vraiment merveilleuse de cette dépendance complexe que cette marge est trop étroite pour contenir.


Vous pouvez lire cette question là où il y a beaucoup de discussions sur cette question et de nombreux liens vers des matériaux à l'extérieur, donc: Stackoverflow.com/questions/2246772/...


En bout de ligne est que différents plans entraîneront des temps d'exécution (légèrement ou très) différents. Testez avec Vos données , dans votre machine, avec différentes tailles de table et paramètres utilisent le meilleur dans votre cas. (Si le cours est le signe que la requête est lente. Si cela fonctionne assez rapidement, pas besoin de passer du temps à optimiser).


J'ai essayé de ne pas exister (seulement après avoir frappé ma tête sur la solution de jointure) mais elle a explosé dans mon visage (et j'étais plutôt prudent). Au moins dans mon expérience, j'ai trouvé tout ce qui concerne les sous-solutions pour être considérablement moins performantes que (prudent). Mais je travaille avec MySQL5, donc bien sûr ymmv. Là encore, ce gars Oracle suggère de réécrire les sous-requêtes comme jointures pour améliorer les performances: dba-oracle.com/oracle_tips_subq_rewrite. HTM


@podperson, oracle conseil ne fonctionne pas pour MySQL, ils sont très différents sous le capot. Suivez les conseils de Ypercube, seuls les tests vous indiqueront (aussi MySQL est très différent de la version à la version).


@podperson: "" a explosé dans mon visage " comme", il n'a pas fonctionné de donner une erreur "ou comme" Ça courait, mais n'a pas donné ce que je m'attendais "ou" Ça courait correctement, mais c'était dévastateur lent "?


@YPERCUBE "Il a couru et apporté le serveur à ses genoux".


@podperson: Pouvez-vous fournir le plan d'exécution? (et les index sur les 2 tables)?


Été un moment, mais je peux vous dire que tous les champs pertinents pour la requête étaient indexés.