SQL соединяется с CASE и WHERE - PullRequest
2 голосов
/ 31 июля 2009

У меня есть три таблицы - одна для тарифов доставки, одна для продуктов и одна для исключений из тарифа на доставку для определенных продуктов. Доставка оплачивается следующим образом: Каждый продукт имеет стоимость доставки, но эта цена может быть отменена исключением. Если для продукта не существует исключений, для тарифа доставки, выбранного пользователем, используется ставка по умолчанию. альтернативный текст http://mi6.nu/sqljoin.png Я пытаюсь объединить эти таблицы, чтобы, если существует исключение, была выбрана эта цена, в противном случае выбирается цена по умолчанию, но у меня возникают проблемы с объединением. Мне нужно запросить по идентификатору продукта, и у меня есть (строка 2 для отладки)

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

И мне нужно вернуть:

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

Таким образом, если существует исключение, используется цена исключения, в противном случае используется цена по умолчанию. Я планирую использовать оператор CASE, но сначала мне нужно вернуть данные.

Ответы [ 4 ]

8 голосов
/ 31 июля 2009

Почему бы не использовать коалесц

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

Таким образом, если e.rate равно null, используется r.rate.

Вы также должны добавить свой e.ProductId в объединение, чтобы оно не заставляло вас выбирать только продукты с исключениями

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
4 голосов
/ 31 июля 2009

Первое, что я заметил, это то, что у вас есть условие предиката в таблице e, которая находится на "внешней" стороне внешнего соединения. Это немедленно превратит объединение во внутреннее объединение, так как строки, которые обычно создаются, где есть запись на внутренней стороне, но нет записи на внешней стороне, будут иметь все нули в столбцах внешней таблицы время выполнения предиката предложения where (WHERE e.ProductID = 48).

Вместо этого вы должны поместить этот предикат в условия соединения.
как это:

 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

Далее, как рекомендовал ответ Джоэлса, для простого выражения, хотя регистр будет работать, вам не нужен оператор регистра, достаточно Coalesce:

 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
1 голос
/ 31 июля 2009

Если вы используете MSSQL, функция COALESCE поможет. Сначала возвращается not-null.

Это так, select COALESCE(shippingexceptions.Rate, shipping.Rate )

сделать то же самое с делом .. когда:

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

Надеюсь, это поможет ..

0 голосов
/ 31 июля 2009
SELECT  COALESCE(
        (
        SELECT  TOP 1 cost
        FROM    shippingexceptions se
        WHERE   se.ShippingRateID = r.id
                AND se.ProductID = 48
        ), DefaultPrice
        ) AS price
FROM    shipping r

или 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...