2009-02-03 6 views
11

J'essaie d'écrire une requête pour rechercher des enregistrements qui n'ont pas d'enregistrement correspondant dans une autre table.Recherche d'enregistrements sans correspondance avec SQL

Par exemple, j'ai deux tables dont les structures ressemble à quelque chose comme ceci:

 
Table1 
    State | Product | Distributor | other fields 
    CA | P1  | A   | xxxx 
    OR | P1  | A   | xxxx 
    OR | P1  | B   | xxxx 
    OR | P1  | X   | xxxx 
    WA | P1  | X   | xxxx 
    VA | P2  | A   | xxxx 

Table2 
    State | Product | Version | other fields 
    CA | P1  | 1.0 | xxxx 
    OR | P1  | 1.5 | xxxx 
    WA | P1  | 1.0 | xxxx 
    VA | P2  | 1.2 | xxxx 

(. État/produit/distributeur forment ensemble la clé pour Tableau1 Etat/produit est la clé pour Tableau2)

Je souhaite trouver toutes les combinaisons État/Produit/Version qui n'utilisent pas le distributeur X. (Le résultat dans cet exemple est donc CA-P1-1.0 et VA-P2-1.2.)

Toutes suggestions sur une requête pour le faire?

+0

de votre deuxième à la dernière phrase, devrait être impliqué table2 même dans cette requête? (sauf peut-être pour obtenir la version du produit). – Tundey

+0

Je pense que vous avez répondu à votre propre question. Table2 est nécessaire pour obtenir la version. –

Répondre

24
SELECT 
    * 
FROM 
    Table2 T2 
WHERE 
    NOT EXISTS (SELECT * 
     FROM 
      Table1 T1 
     WHERE 
      T1.State = T2.State AND 
      T1.Product = T2.Product AND 
      T1.Distributor = 'X') 

Ceci devrait être conforme à la norme ANSI.

+0

Cela fonctionne sur la plupart des systèmes SQL; SAUF ne fonctionnera pas partout (bien qu'il soit plus élégant où cela fonctionne). –

+0

L'utilisation de "SELECT 1 FROM" dans la sous-requête (au lieu de "SELECT * FROM") peut empêcher un balayage de table inutile. Bien que je m'attendrais à ce que le SGBD soit assez intelligent pour le comprendre par lui-même, en voyant "EXISTS". – Tomalak

+1

Je l'ai avec mon collègue SQL Server MVP tout le temps :-) Le * est développé au moment de la compilation, bt s'effondre trivialement, mais pas l'exécution dit-il. Il m'a montré un article une fois. J'ai vu Itzak Ben-Gan il y a un moment et il m'a dit que le * est plus rapide. Le choix est à vous ... – gbn

1

select * from table1 où l'état non (sélectionnez l'état de table1 où le distributeur = 'X')

Probablement pas le plus intelligent, mais qui devrait fonctionner.

+0

IN n'est pas aussi bien que EXISTS, et ne gère pas la clé composite sur l'état/produit – gbn

+1

En outre, selon le SGBDR, 'NOT IN' ne se comporte pas comme vous vous y attendiez si' state' est nullable. –

8

Dans T-SQL:

SELECT DISTINCT Table2.State, Table2.Product, Table2.Version 
FROM Table2 
    LEFT JOIN Table1 ON Table1.State = Table2.State AND Table1.Product = Table2.Product AND Table1.Distributor = 'X' 
WHERE Table1.Distributor IS NULL 

Pas requis sous-requêtes. Edit: Comme les commentaires l'indiquent, DISTINCT n'est pas nécessaire. Merci!

+0

Je n'utiliserais pas distinct, mais sinon c'est ce que vous voulez. – HLGEM

+0

Le distinct rendra probablement la requête moins efficace, mais jamais plus efficace. Cela dépend du nombre de lignes de table relatives. Le distcnt force également un agrégat dont la sous-requête n'a pas besoin. – gbn

+1

Les performances et le comportement de cette requête dépendent également fortement du fait que 'Distributor' est couvert par l'index utilisé dans la jointure (sinon, une recherche peut être requise ou une opération d'index doit être convertie en une opération d'index clusterisée) 'Distributor' est NULLable (auquel cas il peut renvoyer des lignes correspondantes qui manquent une valeur, en plus des lignes sans correspondance). –

1
SELECT DISTINCT t2.State, t2.Product, t2.Version 
FROM table2 t2 
JOIN table1 t1 ON t1.State = t2.State AND t1.Product = t2.Product 
       AND t1.Distributor <> 'X' 
1

Dans Oracle:

SELECT t2.State, t2.Product, t2.Version 
FROM Table2 t2, Table t1 
WHERE t1.State(+) = t2.State 
    AND t1.Product(+) = t2.Product 
    AND t1.Distributor(+) = :distributor 
    AND t1.State IS NULL 
Questions connexes