JOINTURE SQL de la Requête pour renvoyer les lignes où nous n'avons PAS trouver une correspondance dans la table jointe
Plus d'une théorie de la logique de la question, mais ce que j'ai est de deux tables: links
et options
. Liens est un tableau où j'ai ajouter des lignes qui représentent un lien entre un ID de produit (dans un autre products
table) et une option. Le options
table contient toutes les options disponibles.
Ce que je suis en train de faire (mais qui peine à créer de la logique d') est à joindre les deux tables, de retourner uniquement les lignes où il n'y a pas de lien option dans le links
table, donc représentant de laquelle les options sont toujours disponibles pour ajouter le produit.
Est-il une fonctionnalité de SQL qui pourrait m'aider ici? Je ne suis pas énormément d'expérience avec SQL encore.
- Recherche
LEFT JOIN
etNOT EXISTS
- Ce db plateforme utilisez-vous? Le Tag en question.
Vous devez vous connecter pour publier un commentaire.
Votre table design sonne bien.
Si cette requête renvoie le
id
valeurs de la "options", liée à un "produit"...Ensuite cette requête serait d'obtenir le détail de toutes les options liées à l' "produit"
Noter que nous pouvons déplacer le
"product_id='foo'"
prédicat de la clause where la clause de le REJOINDRE, pour un résultat équivalent, par exemple(Non pas que cela fait une différence ici, mais cela fait une différence si nous étions à l'aide d'une JOINTURE EXTERNE (dans la clause where, il irait à l'encontre de l ' "extérieur-ness" de la jointure, et de la rendre équivalente à une JOINTURE INTERNE.)
Mais, rien de tout cela répond à votre question, il ne met en scène pour répondre à votre question:
Comment pouvons-nous obtenir les lignes de "options" qui ne sont PAS liés au produit en particulier?
L'approche la plus efficace est (généralement) un anti-rejoindre modèle.
Ce que c'est, nous aurons toutes les lignes de "options", ainsi que toutes les lignes correspondantes de "liens" (pour un particulier product_id, dans votre cas). L'ensemble des résultats comprendront les lignes de "options" qui n'ont pas de ligne correspondante dans "liens".
Le "truc" est de filtrer toutes les lignes ayant pas de ligne correspondante(s) trouvé dans la section "liens". Qui nous laisse avec seulement les lignes qui n'ont pas un match.
Et de la façon dont nous le filtre de ces lignes, nous utilisons un prédicat de la clause where qui vérifie si une correspondance a été trouvée. Nous faisons cela en cochant une colonne que l'on sait pour certains sera PAS NULL si une ligne correspondante a été trouvé. Et nous savoir* pour certains cette colonne sera NULL si une ligne correspondante a été PAS trouvé.
Quelque chose comme ceci:
La
"LEFT"
mot clé indique un "extérieur" se joindre à l'opération, nous obtenons toutes les lignes de "options" (la table sur le côté "gauche" de la JOINTURE), même si une ligne correspondante n'est trouvée. (Normal inner join filtre les lignes qui n'ont pas un match.)Le "truc" est dans la clause where... si nous avons trouvé une ligne correspondante à partir de liens, nous savons que la
"option_id"
colonne retournée à partir de"links"
ne serait pas NULLE. Il ne peut pas être NULL si il "vaut" quelque chose, et nous savons qu'il y avait à "équivaut à" quelque chose parce que le prédicat de la clause.Donc, nous savons que les lignes d'options qui n'ont pas un match qui aura une valeur NULL pour cette colonne.
Il prend un peu pour obtenir votre cerveau enroulé autour de lui, mais de l'anti-rejoindre rapidement devient un motif familier.
Les "anti-rejoindre le" patron n'est pas la seule façon d'obtenir l'ensemble des résultats. Il ya un couple de d'autres approches.
Une option est d'utiliser une requête avec un
"NOT EXISTS"
prédicat avec une sous-requête corrélée. C'est un peu plus facile à comprendre, mais n'a pas l'habitude de faire ainsi:Qui dit me faire toutes les lignes de la table options. Mais pour chaque ligne, l'exécution d'une requête, et de voir si une ligne correspondante "existe" dans le tableau de liens. (Il n'a pas d'importance ce qui est retourné dans la liste de sélection, nous ne sommes qu'à tester si elle renvoie au moins une ligne... je utiliser un "1" dans la liste de sélection pour me rappeler que je suis à la recherche de "1 ligne".
Ce n'est généralement pas aussi performants que les anti-jointure, mais parfois c'est de courir plus vite, surtout si d'autres prédicats dans la clause where de la requête externe filtre près de chaque rangée, et la sous-requête n'a qu'à exécuter pour un couple de lignes. (C'est, quand nous n'avons qu'à vérifier quelques aiguilles dans une botte de foin. Lorsque nous avons besoin pour traiter l'ensemble de la pile de foin, l'anti-modèle de jointure est généralement plus rapide.)
Et le débutant requête que vous avez le plus de chances de voir est une
NOT IN (subquery)
. Je ne vais même pas donner un exemple de cela. Si vous avez une liste de littéraux, puis par tous les moyens, de l'utilisation d'un PAS. Mais avec une sous-requête, c'est rarement le meilleur interprète, s'il ne semble pas être le plus facile à comprendre.Oh, ce que le foin, je vais vous donner une démonstration de ce que bien (pas que je suis en vous encourageant à faire de cette façon):
Que la sous-requête (à l'intérieur des parenthèses) obtient une liste de tous les option_id valeurs associées à un produit.
Maintenant, pour chaque ligne dans les options (dans la requête externe), nous pouvons vérifier la valeur de l'id pour voir si il est dans la liste retournée par la sous-requête.
Si nous avons une garantie que option_id ne sera jamais NULLE, on peut omettre le prédicat que les tests pour
"option_id IS NOT NULL"
. (Dans le cas général, quand un NUL se glisse dans le jeu de résultats, alors que l'extérieur de la requête ne peut pas dire si l'o.l'id est dans la liste ou pas, et la requête ne renvoie aucune ligne; alors j'ai l'habitude comprennent que, même quand il n'est pas nécessaire. LeGROUP BY
n'est pas strictement nécessaire, surtout si il y a une contrainte unique (garantie de l'unicité) sur le (produit_id,option_id) n-uplet.Mais, une fois encore, ne pas utiliser
NOT IN (subquery)
, sauf pour les essais, sauf si il y a un peu raison impérieuse (par exemple, il parvient à faire mieux que les anti-join).Vous avez peu de chances de percevoir des différences de performances avec de petits ensembles, les frais généraux de la transmission de la déclaration, l'analyser, la génération d'un plan d'accès, et le retour des résultats des nains de la "réalisation" du temps du régime. C'est avec des ensembles plus larges que les différences de "l'exécution" le temps est devenu apparent.
EXPLAIN SELECT ...
est un très bon moyen d'obtenir une poignée sur les plans d'exécution, pour voir ce que MySQL est vraiment en train de faire avec votre déclaration.Index appropriés, en particulier la couverture des index, peut sensiblement améliorer les performances de certains états.
Oui, vous pouvez faire un
LEFT JOIN
(si MySQL; il y a des variantes dans d'autres dialectes) qui comprendra des lignes de liens qui n'ont PAS de correspondance dans les options. Puis tester sioptions.someColumn
IS NULL
et vous aurez exactement les lignes de liens qui n'avaient pas de "correspondant à la ligne" dans les options.WHERE
clause peut faire le test pour voir si une ligne correspondante est trouvée. C'est un familier de l'anti-modèle de jointure; une fois que vous obtenez votre cerveau enroulé autour de la notion, il deviendra une seconde nature pour vous. J'ai expliqué à ma réponse.Essayer quelque chose le long des lignes de cette
À compter
Pour voir les lignes