2013-02-11 3 views
0

Compte tenuSQL JOIN Avec Repli

CREATE TABLE Addresses 
    Id INT NOT NULL 
    Zip NVARCHAR(5) NULL  
    ZipPlus4 NVARCHAR(9) NULL 

CREATE TABLE ZipLookup 
    Zip NVARCHAR(5) NULL  
    Code NVARCHAR(10) NULL 

CREATE TABLE ZipPlus4Lookup 
    ZipPlus4 NVARCHAR(9) NULL  
    Code NVARCHAR(10) NULL 

et données comme

Addresses 
1 | 92123 | 921234444 

ZipLookup 
92123 | Type A 

ZipPlus4Lookup 
921234444 | Type B 

Est-il possible de construire une requête telle que:

  • Une ligne donnée dans les adresses est externe joint à ZipPlus4Lookup s'il y a un match

    Addresses.ZipPlus4 = ZipPlus4Lookup.ZipPlus4

  • Sinon, la ligne donnée dans les adresses est externe reliée à ZipLookup s'il existe une correspondance

    Addresses.Zip = ZipLookup.Zip

  • Sinon ni table est externe a rejoint

En clair, la table d'adresses a un code postal et une colonne ZipPlus4 et je dois rechercher un code en utilisant le match le plus précis. S'il y a une correspondance sur Zip + 4, utilisez le code de cette correspondance. Sinon, utilisez le code d'une correspondance Zip.

Je souhaite avoir une tentative de requête à partager, mais avec celui-ci, je ne sais pas par où commencer.

+0

Quelle version de SQL Server? – ErikE

Répondre

5

Cette requête de base fonctionnera:

SELECT 
    A.*, 
    Code = IsNull(Z4.Code, Z.Code) 
FROM 
    dbo.Addresses A 
    LEFT JOIN dbo.ZipPlus4Lookup Z4 
     ON A.ZipPlus4 = Z4.ZipPlus4 
    LEFT JOIN dbo.ZipLookup Z 
     ON A.Zip = Z.Zip 
     AND Z4.ZipPlus4 IS NULL; 

Ou vous pouvez essayer quelque chose comme ceci:

SELECT 
    A.*, 
    Z.Code 
FROM 
    dbo.Addresses A 
    OUTER APPLY (
     SELECT TOP 1 Code 
     FROM (
     SELECT 0, Code FROM dbo.ZipPlus4Lookup Z4 
     WHERE A.ZipPlus4 = Z4.ZipPlus4 
     UNION ALL 
     SELECT 1, Code FROM dbo.ZipLookup Z 
     WHERE A.Zip = Z.Zip 
    ) X (Seq, Code) 
     ORDER BY X.Seq 
    ) Z; 

Ils peuvent avoir des caractéristiques de performance. Ça vaut le test. Ma conjecture est que la deuxième requête est inutile, mais il est encore conceptuellement possible d'être meilleur.

Voir dans l'action in a SQL Fiddle.

+0

Je ne comprends pas 'ET Z4.ZipPlus4 IS NULL'. La table ZipPlus4Lookup réelle n'aura aucune entrée NULL, mais plutôt il n'y a peut-être aucune correspondance. Qu'est-ce que cette ligne accomplit? –

+0

Puisque la jointure à 'Zip4PlusLookup' est un' LEFT JOIN ', dans le dernier rowset *, toute colonne * dans 'ZipPlus4Lookup' pour une' Address' avec une correspondance 'ZipPlus4' échouée sera NULL. Puisque la condition 'IS NULL' est * en dehors de * et * après * la jointure de' ZipPlus4Lookup', cela donnera à l'optimiseur de requête une chance d'optimiser la condition finale si la recherche Z4 a déjà réussi. Notez que mettre la condition 'Z4.ZipPlus4 IS NULL' dans son propre' LEFT JOIN' ferait exactement ce que vous suggérez - empêchez n'importe quelle correspondance de fonctionner du tout. – ErikE

+0

@EricJ .: Le 'AND Z4.ZipPlus4 IS NULL' signifie seulement joindre' ZipLookup' s'il n'y a pas de correspondance dans 'ZipPlus4Lookup'. Ce n'est pas vraiment nécessaire, car 'IsNull (Z4.Code, Z.Code)' ignorera 'ZipLookup' si une correspondance' ZipPlus4Lookup' est trouvée de toute façon, mais peut-être que cela a un impact positif sur les performances (je ne suis pas sûr). – gmm