2017-01-10 6 views
1

Я думаю, что это будет проще, чтобы показать пример первым, а затем объяснить:саз с условием

SELECT P.ID, 
(CASE WHEN PC.NewCostPrice IS NULL 
THEN P.Cost ELSE MAX(PC.Date) PC.NewCostPrice 
END) 
FROM price AS P 
LEFT OUTER JOIN priceChange as PC 
ON P.ID = PC.ID 

Таким образом, в примере, если NewCostPrice IS NULL, что означает, что не было изменение цены, то Я хочу нормальную стоимость (P.Cost). Однако, если бы произошло изменение цены, я хочу получить последнее (MAX (Date)) изменение цены. Я не уверен, как включить это в инструкцию CASE.

Я чувствую, что это можно сделать с помощью подзапроса и наличия предложения, но это не сработало, когда я попытался. Какие-либо предложения?

Спасибо!

+0

ли 'ID' первичный ключ в указанных таблицах ? – ydoow

ответ

2

Легкий способ

SELECT distinct P.ID, 
    ISNULL((SELECT TOP 1 PC1.NewCostPrice FROM priceChange as PC1 WHERE PC1.ID = p.id ORDER BY PC1.Date DESC), p.cost) 
    FROM price AS P 
-1
SELECT P.ID 
      ,(CASE 
       WHEN PC.NewCostPrice IS NULL 
        THEN P.Cost 
       ELSE (SELECT TOP 1 PC1.NewCostPrice 
         FROM priceChange PC1 
         WHERE PC1.ID = PC.ID 
         GROUP BY PC1.NewCostPrice, PC1.Date 
ORDER BY PC1.Date DESC 
        ) 
       END 
      ) 
    FROM price AS P 
    LEFT OUTER JOIN priceChange as PC 
    ON P.ID = PC.ID 
+0

Спасибо за быстрый ответ Сэм!Тем не менее, это на самом деле не получилось, это выбор неправильных значений ... Мне нужно будет выяснить, почему, может быть, неправильная дата, которую я угадываю. Также мне пришлось добавить «SELECT TOP 1» в подзапрос, а предложение HAVING потребовало условия, поэтому я добавил «HAVING PC1.Date = MAX (PC1.Date)» – Austin

+0

Прошу прощения. Проверьте обновленный ответ. – Sam

3

Есть два подхода, которые вы могли бы рассмотреть - я бы испытал оба, чтобы видеть, что лучше работает для вашей ситуации.

  1. Используйте в подзапросе ROW_NUMBER(), чтобы найти последнее изменение цены всех ценовых изменений, затем присоединяйтесь к ним по цене, чтобы получить правильную цену.
  2. Использование коррелируется подзапрос (много способов этого, либо в SELECT, как в другой ответ или с OUTER APPLY), чтобы получить только самое последнее изменение цены для каждой строки цен

Если ваша таблица цен очень велик, и вы сразу получают большое количество цен, метод # 1, вероятно, будет лучше, поэтому коррелированный подзапрос не будет выполняться для каждой отдельной строки набора результатов.

Если ваш окончательный запрос отбрасывает относительно небольшое количество записей вместо огромных наборов результатов для вашего сервера, тогда коррелированный подзапрос может быть лучше для вас.

1. ROW_NUMBER() подход

SELECT 
    P.ID, 
    COALESCE(PC.NewCostPrice, P.Cost) AS LatestPrice 
FROM Price AS P 
    LEFT OUTER JOIN (
     SELECT 
      ID, 
      ROW_NUMBER() OVER (PARTITION BY ID 
       ORDER BY [Date] DESC) AS RowId, 
      NewCostPrice 
     FROM PriceChange 
    ) PC 
     ON P.ID = PC.ID 
      AND PC.RowId = 1 -- Only most recent 

2a. Коррелированные подзапросы (SELECT)

SELECT 
    P.ID, 
    COALESCE((
     SELECT TOP 1 
      NewCostPrice 
     FROM PriceChange PC 
     WHERE PC.ID = P.ID 
     ORDER BY PC.[Date] DESC 
    ), P.Cost) AS LatestPrice 
FROM Price AS P 

2b. Коррелированные подзапросы с OUTER APPLY

SELECT 
    P.ID, 
    COALESCE(PC.NewCostPrice, P.Cost) AS LatestPrice 
FROM Price AS P 
    OUTER APPLY (
     SELECT TOP 1 
      NewCostPrice 
     FROM PriceChange PC 
     WHERE PC.ID = P.ID 
     ORDER BY PC.[Date] DESC 
    ) PC 

Используете ли вы 2a или 2b, скорее всего, предпочтение в том, как вы хотите сохранить запрос идти вперед.

0

Здесь я полагаю, что PC.ID не является основным ключом, или нет смысла присоединяться к ID, хотя может быть иная цена на тот же товар.

Из вашего запроса я предполагаю, что вы просто хотите, чтобы принести последний NewCostPrice отсортирован по Date, присоединившись priceChange

SELECT 
    P.ID, 
    CASE 
     WHEN PC.NewCostPrice IS NULL THEN P.Cost 
     ELSE PC.NewCostPrice      
    END AS NewPrice 
FROM 
    price AS P 
LEFT JOIN 
    (SELECT *, RANK() OVER (PARTITION BY ID ORDER BY [Date] DESC) as rk FROM priceChange) PC ON P.ID = PC.ID AND PC.rk = 1