2009-07-31 10 views
2

Ich habe drei Tabellen - eine für Versandkosten, eine für Produkte und eine für Ausnahmen zu Versandkosten für bestimmte Produkte. Der Versand wird wie folgt berechnet: Jedes Produkt hat einen Versandpreis, aber dieser Preis kann durch eine Ausnahme überschrieben werden. Wenn für ein Produkt keine Ausnahme besteht, wird die Standardrate für die vom Benutzer ausgewählte Versandrate verwendet. alt text http://mi6.nu/sqljoin.png Ich versuche, diese Tabellen so zu verbinden, dass, wenn eine Ausnahme existiert, dieser Preis ausgewählt wird, andernfalls wird der Standardpreis ausgewählt, aber ich habe Probleme mit dem Join. Ich muss nach Produkt-ID abfragen, und ich habe (Linie 2 ist für das Debuggen)SQL Join mit CASE und WO

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 

Und ich zurück brauchen:

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

Also, wenn eine Ausnahme existiert, wird die Ausnahme Preis, sonst Der Standardpreis wird verwendet. Ich plane, eine CASE-Anweisung zu verwenden, aber ich muss die Daten zuerst zurückgeben.

+0

Was Ihre Frage ist? – hobodave

Antwort

4

Das erste, was ich ist bemerken zu wählen, dass Sie eine Prädikatbedingung auf dem Tisch e haben, das ist auf der "äußeren" Seite eines äußeren Joins. Dadurch wird die Verknüpfung sofort in eine innere Verknüpfung umgewandelt, da die Zeilen, die normalerweise erstellt wurden, wenn auf der inneren Seite ein Datensatz vorhanden ist, aber keine Aufzeichnung auf der äußeren Seite, alle Nullwerte in den Spalten von der äußeren Tabelle haben Zeit das Prädikat der where-Klausel (WHERE e.ProductID = 48) wird ausgeführt.

Sie müssen dieses Prädikat stattdessen in die Join-Bedingungen einfügen.
wie folgt aus:

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 

Als nächstes, wie Joels Antwort empfohlen, für einen einfachen Ausdruck, obwohl ein Fall funktionieren würde, Sie eine Case-Anweisung nicht benötigen, werden Coalesce genügen:

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 für eine gute Erklärung, warum e.ProductId auf dem Join gehört. – Joel

+0

Danke, ich verstehe, warum das funktioniert. Ich hatte eigentlich keine Ahnung, dass du dich mit AND verbinden könntest. Etwas, was du lernst, während du mitläufst, denke ich. :) – Echilon

8

Warum verwenden Sie einen coalesce nicht

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 

diese Weise, wenn e.rate null ist, r.rate verwendet wird.

Sie sollten auch Ihre e.ProductId auf das setzen verbinden, damit es nicht Sie zwingen, nur Produkte mit Ausnahmen

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

Ein "l" in Koaleszenz - nicht zwei. Ansonsten eine großartige Antwort und ein sehr guter Punkt bezüglich der WHERE-Klausel; Ich habe nicht bemerkt, dass das OP das getan hat. –

+0

Heh, danke. Ich bin Programmierer, kein englischer Major. Normalerweise verlasse ich mich auf Syntax-Checker und Compiler für diese Dinge.;) – Joel

+0

Sie können auch ISNULL verwenden, ich bin mir nicht sicher, ob es einen Leistungsvorteil gegenüber COALESCE gibt, wenn Sie nur zwei auszuwertende Ausdrücke haben. –

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 

oder in 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

Wenn Sie auf MSSQL sind, CO ALESCE-Funktion würde helfen. Es gibt zuerst nicht-null zurück.

Es ist select COALESCE(shippingexceptions.Rate, shipping.Rate)

die gleiche Sache mit Fall tun .. wenn:

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

this helps ..