SQL min (), max ()

У меня есть таблица с историей цен на товары (ProductCostHistory). Столбцы: ProductID (PK, FK), StartDate (PK), EndDate, StandardCost, ModifiedDate.

Вот как выглядит таблица:

ProductID   StartDate   EndDate     StandardCost    ModifiedDate
707         2011-05-31  2012-05-29  12,0278        2012-05-29
707         2012-05-30  2013-05-29  13,8782        2013-05-29
707         2013-05-30      NULL    13,0863        2013-05-16
708         2011-05-31  2012-05-29  12,0278        2012-05-29 
708         2012-05-30  2013-05-29  13,8782        2013-05-29
708         2013-05-30  NULL        13,0863        2013-05-16

Для каждого продукта, который я хочу просмотреть: Текущая цена, самая высокая и самая низкая историческая цена.

Это мой код:

USE AdventureWorks2014
GO
SELECT Distinct ProductCostHistory.ProductID, ProductCostHistory.StandardCost, MAX(ProductCostHistory.StandardCost) AS HighestPrice, MIN(ProductCostHistory.StandardCost) AS LowestPrice FROM Production.ProductCostHistory
GROUP BY ProductID, StandardCost
Order by ProductID

Результат выглядит так:

ProductID   StandardCost    HighestPrice    LowestPrice
707         12,0278         12,0278         12,0278
707         13,0863         13,0863         13,0863
707         13,8782         13,8782         13,8782
708         12,0278         12,0278         12,0278
708         13,0863         13,0863         13,0863
708         13,8782         13,8782         13,8782

Но я хочу больше так (пример):

PRoductID    StandardCost    HighestPrice     LowestPrice
707          13,0863         13,8787          12,0278
708          12,0278         13,8782          12,0278

Спасибо


person Carl Decks    schedule 31.10.2017    source источник
comment
Почему для продукта 707 требуется MAX StandardCost, а для продукта 708 MIN? Есть ли для этого какое-то правило?   -  person Andrey Belykh    schedule 31.10.2017
comment
Почему ProductCostHistory выбрано, а не выводится?   -  person Jelle    schedule 31.10.2017
comment
Имя таблицы - ProductCostHistory. Я хочу знать 3 вещи для каждого продукта. 1: Текущая цена. 2: Самая высокая цена за этот продукт в истории. 3. Самая низкая цена на этот продукт в истории.   -  person Carl Decks    schedule 31.10.2017
comment
Как определяется Текущая цена?   -  person Matthew Hart    schedule 31.10.2017
comment
@CarlDecks Как определяется текущая цена? Для productid 707 вы выбираете среднюю строку, а для 708 вы выбираете первую строку (из 708)   -  person Simon    schedule 31.10.2017
comment
Извините за непонятность. Я отредактировал вопрос   -  person Carl Decks    schedule 31.10.2017
comment
Текущая цена должна определяться EndDate = null, я полагаю ?.   -  person Carl Decks    schedule 31.10.2017
comment
Как 12 0278 текущая цена для 708, закончившейся 2012-05-29?   -  person Parfait    schedule 31.10.2017


Ответы (4)


Рассмотрите возможность использования условного агрегирования для CurrentPrice:

SELECT h.ProductID, 
       MAX(CASE WHEN h.EndDate IS NULL THEN h.StandardCost END) AS CurrentPrice,
       MAX(h.StandardCost) AS HighestPrice, 
       MIN(h.StandardCost) AS LowestPrice 
FROM Production.ProductCostHistory h
GROUP BY h.ProductID
ORDER BY h.ProductID
person Parfait    schedule 31.10.2017
comment
Спасибо! Я борюсь с курсом для начинающих по SQL :) - person Carl Decks; 31.10.2017

Вот один способ ... выберите текущую запись, а затем присоединитесь к подзапросу min / max по идентификатору продукта.

select p.ProductID, p.StandardCost, g.MaxPrice, g.MinPrice
from ProductCostHistory p
inner join (select ProductID, MAX(StandardCost) as MaxPrice, MIN(StandardCost) as MinPrice
            from ProductCostHistory group by ProductID) g
  on g.ProductID = p.ProductID
where p.StartDate <= GETDATE() AND (p.EndDate > GETDATE() OR p.EndDate IS NULL)

SQL Fiddle

person stephen.vakil    schedule 31.10.2017
comment
Спасибо за помощь :) - person Carl Decks; 31.10.2017

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

Я думаю, что ниже запрос должен работать для вас

ВЫБЕРИТЕ productid, MAX (StandardCost), MIN (StandardCost) FROM ProductCostHistory GROUP BY productid

person user3506602    schedule 31.10.2017

Ваша проблема заключается в том, что Product.StandardCost не входит в функцию Aggregate.

Вам нужен второй столбец в запрошенном желаемом выходе? Я мог бы понять, что это полезно, если бы вы взяли среднее значение, но в текущем примере я не думаю, что имеет смысл включать его?

Это должно работать:

USE AdventureWorks2014
GO
SELECT ProductCostHistory.ProductID, MAX(ProductCostHistory.StandardCost) AS HighestPrice, MIN(ProductCostHistory.StandardCost) AS LowestPrice 
FROM Production.ProductCostHistory
GROUP BY ProductID
Order by ProductID

************ РЕДАКТИРОВАТЬ ************

С дополнительной информацией, которую вы предоставили о стартовой таблице, следующее будет делать то, что вам нужно:

WITH CTE_AggregatePrices AS
(
  SELECT ProductID
    ,  MAX(StandardCost) AS HighestPrice
    ,  MIN(StandardCost) AS LowestPrice 
  FROM ProductCostHistory
  GROUP BY ProductID
)
SELECT PCH.ProductID
    ,  PCH.StandardCost
    ,  CAP.HighestPrice
    ,  CAP.LowestPrice
FROM ProductCostHistory AS PCH
INNER JOIN CTE_AggregatePrices AS CAP ON PCH.ProductID = CAP.ProductID
WHERE PCH.EndDate IS NULL;

Хорошо, поэтому я использовал CTE (общее табличное выражение), чтобы получить требуемые агрегаты (цены MIN и MAX), мне нравятся CTE, потому что они просты и легко читаются, но они не всегда лучший путь вперед , однако в данном случае он вполне отвечает всем требованиям.

Таким образом, с цифрами MIN и MAX, изолированными от каждого ProductID, это просто случай получения текущей цены, которая на основе вашего примера данных представляет собой простое предложение WHERE, которое проверяет, выполняется ли EndDate равно NULL. Мы объединяем результаты этого с совокупным CTE по ProductID, что позволяет нам отображать текущую цену с самой высокой и самой низкой ценой для продукта.

Поскольку это задание, пожалуйста, найдите время, чтобы убедиться, что именно об этом вас просили, и что вы понимаете, что происходит. Например, если ваш курс еще не охватывал CTE, я очень сомневаюсь, что они ищут этот ответ, даже если он действителен. Вы можете получить тот же результат, используя подзапрос:

SELECT PCH.ProductID
    ,  PCH.StandardCost
    ,  CAP.HighestPrice
    ,  CAP.LowestPrice
FROM ProductCostHistory AS PCH
INNER JOIN 
(
  SELECT ProductID
    ,  MAX(StandardCost) AS HighestPrice
    ,  MIN(StandardCost) AS LowestPrice 
  FROM ProductCostHistory
  GROUP BY ProductID
) AS CAP ON PCH.ProductID = CAP.ProductID
WHERE PCH.EndDate IS NULL;
person Landy81    schedule 31.10.2017
comment
Да, мне тоже нужна текущая цена. Текущая цена определяется EndDate = null, я думаю ?. Это часть школьного задания - person Carl Decks; 31.10.2017
comment
@CarlDecks А, эта дополнительная информация имеет значение. См. Редактирование выше. - person Landy81; 01.11.2017