У меня есть три таблицы:
Человек
Группа продуктов
Цена каждой группы продуктов для человека с датой
Мне нужен результат ниже, который показывает цену последней даты каждой группы продуктов.
Помогите мне, пожалуйста.
Я получаю результат, создавая таблицу, а затем устанавливая ячейку за ячейкой
Но я хочу это в одном запросе
Если группы A–C многочисленны или переменны, вам придется изучить Dynamic SQL или перейти на уровень представления.
Этот вопрос похож на: Получите по 1 верхней строке каждой группы. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.
Пожалуйста, не используйте изображения для данных, используйте уценку таблицы.
К вашему сведению, в базах данных есть строки и столбцы, а не ячейки.
Вы можете использовать PIVOT, чтобы получить результаты в одном запросе.
select
isnull(MAX([Group C]),'') as [Group C]
, isnull(MAX([Group B]),'') as [Group B]
, isnull(MAX([Group A]),'') as [Group A]
,FullName, PersonID
from
(
SELECT PGP.*, P.FullName, PG.ProductGroupName, CONVERT(varchar(10),Pricedate,112) + '-' + Price as DatePrice
FROM ProductGroupPrice PGP
INNER JOIN ProductGroup PG ON PG.ProductGroupID=PGP.ProductGroupID
INNER JOIN person P ON P.PersonID=PGP.PersonID
) x
pivot
(
max(DatePrice)
for ProductGroupName in([Group A], [Group B], [Group C])
)p
GROUP BY FullName, PersonID
Это возвращает максимальную цену, я думаю, ОП хотел иметь последнюю цену за дату.
@siggemannen легко исправить. Я просто добавлю к цене дату. Затем я могу просто удалить первые 11 символов для презентации. Я оставлю этот шаг Мохаммаду Кермани
Возможно, вы захотите снова удалить дату. Кроме того, это не сработает, если Price не является VARCHAR, а это, вероятно, не так. Не надо торопиться, лучше сделай все правильно
Логику выбора последней Price
для каждой комбинации ProductGroupID
и PersonID
см. в разделе Получить 1 верхнюю строку каждой группы. Общий метод заключается в использовании оконной функции ROW_NUMBER()
для нумерации строк внутри каждой группы, а затем фильтрации по номеру строки = 1.
После этого останется лишь выполнить операцию PIVOT.
SELECT PVT.[GROUP C], PVT.[GROUP B], PVT.[GROUP A], PVT.FullName, PVT.PersonId
FROM (
SELECT PG.ProductGroupName, PGP.Price, P.FullName, P.PersonId
FROM (
SELECT
*,
ROW_NUMBER()
OVER(PARTITION BY ProductGroupID, PersonID ORDER BY PriceDate DESC)
AS RowNum
FROM ProductGroupPrice
) PGP
JOIN ProductGroup PG
ON PG.ProductGroupID = PGP.ProductGroupID
JOIN person P
ON P.PersonID = PGP.PersonID
WHERE PGP.RowNum = 1
) Q
PIVOT (
MAX(Q.Price)
FOR Q.ProductGroupName IN ([GROUP C], [GROUP B], [GROUP A])
) PVT
ORDER BY PVT.PersonId
Альтернативой использованию PIVOT
является условная агрегация, при которой вы определяете элементы выбора, например MAX(CASE WHEN <condition> THEN <value> END) AS <column>
.
SELECT
MAX(CASE WHEN PG.ProductGroupName = 'GROUP C' THEN PGP.Price END) AS [GROUP C],
MAX(CASE WHEN PG.ProductGroupName = 'GROUP B' THEN PGP.Price END) AS [GROUP B],
MAX(CASE WHEN PG.ProductGroupName = 'GROUP A' THEN PGP.Price END) AS [GROUP A],
P.FullName,
P.PersonId
FROM (
SELECT
*,
ROW_NUMBER()
OVER(PARTITION BY ProductGroupID, PersonID ORDER BY PriceDate DESC)
AS RowNum
FROM ProductGroupPrice
) PGP
JOIN ProductGroup PG
ON PG.ProductGroupID = PGP.ProductGroupID
JOIN person P
ON P.PersonID = PGP.PersonID
WHERE PGP.RowNum = 1
GROUP BY P.FullName, P.PersonId
ORDER BY P.PersonId
Промежуточные результаты:
Окончательные результаты:
См. эту db<>fiddle для демонстрации обоих подходов.
спасибо, это работает. очень хорошо
Найдите «условную агрегацию». Если вам все еще нужна помощь с вашим запросом после поиска техники, вам следует публиковать данные в виде текста, а не изображений. Почему?