2009-07-31 8 views
2

J'ai trois tableaux - un pour les tarifs d'expédition, un pour les produits et un pour les exceptions au taux d'expédition pour des produits particuliers. L'expédition est chargée comme suit: Chaque produit a un prix d'expédition, mais ce prix peut être remplacé par une exception. Si aucune exception n'existe pour un produit, le taux par défaut est utilisé pour le tarif d'expédition sélectionné par l'utilisateur. alt text http://mi6.nu/sqljoin.png J'essaie de joindre ces tables de sorte que si une exception existe, ce prix est sélectionné, sinon, le prix par défaut est sélectionné mais j'ai des problèmes avec la jointure. Je dois interroger par ID de produit, et je (ligne 2 est pour le débogage)SQL Rejoindre CASE et OERE

SELECT r.ID AS ShippingRateID, r.Name, 
e.*, r.* 
FROM shipping r LEFT JOIN shippingexceptions e ON r.ID = e.ShippingRateID 
WHERE e.ProductID = 48 

et je dois retourné:

1 Uk and Northern Ireland 1 
2 EU Eire...  10 
3 US and Canada  2.16 
4 Rest of world  2.44 

Donc, si une existe exception, le prix d'exception est utilisé, sinon le prix par défaut est utilisé. Je prévois d'utiliser une instruction CASE, mais je dois d'abord renvoyer les données.

+0

Quelle est votre question? – hobodave

Répondre

4

La première chose que je remarque est que vous avez une condition sous-jacente sur la table e, qui est sur le côté "externe" d'une jointure externe. Cela transformera immédiatement la jointure en une jointure interne, car les lignes qui auraient normalement été produites là où il y a un enregistrement sur le côté interne mais aucun enregistrement sur le côté extérieur, auront tous les nulls dans les colonnes de la table externe par le time le prédicat de la clause where (WHERE e.ProductID = 48) est exécuté.

Vous devez placer ce prédicat dans les conditions de jointure à la place.
comme ceci:

SELECT r.ID AS ShippingRateID, r.Name, e.*, r.* 
FROM shipping r 
    LEFT JOIN shippingexceptions e 
     ON r.ID = e.ShippingRateID 
      And e.ProductID = 48 

Ensuite, comme Joels réponse recommandée, pour une simple expression, bien qu'un cas fonctionnerait, vous n'avez pas besoin d'une déclaration de cas, COALESCE suffira:

SELECT r.ID AS ShippingRateID, r.Name, 
    Coalesce(e.rate, defaultrate) as Rate, 
    e.*, r.* 
FROM shipping r 
    LEFT JOIN shippingexceptions e 
     ON r.ID = e.ShippingRateID 
      And e.ProductID = 48 
+0

+1 pour une bonne explication de la raison pour laquelle e.ProductId appartient à la jointure. – Joel

+0

Merci, je comprends pourquoi cela fonctionne. En fait, je n'avais aucune idée que vous pourriez vous joindre à ET. Quelque chose que vous apprenez au fur et à mesure je pense. :) – Echilon

8

Pourquoi ne pas utiliser un soudent

SELECT r.ID AS ShippingRateID, r.Name, coalesce(e.cost, r.defaultprice) 
FROM shipping r LEFT JOIN shippingexceptions e ON r.ID = e.ShippingRateID 
WHERE e.ProductID = 48 

De cette façon, si e.rate est nulle, r.rate est utilisé.

Vous devriez également mettre votre e.ProductId sur la jointure ne vous oblige donc à ne pas sélectionner uniquement des produits avec des exceptions

SELECT r.ID AS ShippingRateID, r.Name, coalesce(e.cost, r.defaultprice) 
FROM shipping r LEFT JOIN shippingexceptions e ON r.ID = e.ShippingRateID and e.ProductID = 48 
+0

Un "l" en coalescence - pas deux. Sinon, une bonne réponse, et un très bon point sur la clause WHERE; Je n'ai pas remarqué que le PO avait fait cela. –

+0

Hé, merci. Je suis un programmeur, pas un major anglais. Je m'appuie généralement sur des vérificateurs de syntaxe et des compilateurs pour ce genre de choses.;) – Joel

+0

Vous pouvez également utiliser ISNULL, je ne suis pas sûr s'il y a un avantage de performance par rapport à COALESCE si vous n'avez que deux expressions à évaluer. –

0
SELECT COALESCE(
     (
     SELECT TOP 1 cost 
     FROM shippingexceptions se 
     WHERE se.ShippingRateID = r.id 
       AND se.ProductID = 48 
     ), DefaultPrice 
     ) AS price 
FROM shipping r 

, ou SQL Server 2005+:

SELECT COALESCE(cost, DefaultPrice) AS price 
FROM shipping r 
OUTER APPLY 
     (
     SELECT TOP 1 cost 
     FROM shippingexceptions 
     WHERE ShippingRateID = r.id 
       AND ProductID = 48 
     ) se 
1

Si vous êtes sur MSSQL, CO La fonction ALESCE aiderait. Il retourne d'abord non-nul.

Il est select COALESCE(shippingexceptions.Rate, shipping.Rate)

Faites la même chose avec le cas .. quand:

Select Case when shippingexceptions.Rate is not null THEN shippingexceptions.Rate 
ELSE shipping.Rate 

Hope this helps ..