Как выбрать только первый ROW_NUMBER в сочетании с SUM
Мне нравится группировать свою таблицу по [ID] при использовании SUM, а также возвращать [Product_Name] из верхней части ROW_NUMBER
- не уверен, стоит ли мне использовать ROW_NUMBER
, GROUPING SETS
или перебрать все с помощью FETCH... это то, что я пытался:
DECLARE @SampleTable TABLE
(
[ID] INT,
[Price] MONEY,
[Product_Name] VARCHAR(50)
)
INSERT INTO @SampleTable
VALUES (1, 100, 'Product_1'), (1, 200, 'Product_2'),
(1, 300, 'Product_3'), (2, 500, 'Product_4'),
(2, 200, 'Product_5'), (2, 300, 'Product_6');
SELECT
[ID],
[Product_Name],
[Price],
SUM([Price]) OVER (PARTITION BY [ID]) AS [Price_Total],
ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [ID]) AS [Row_Number]
FROM
@SampleTable T1
Мои желаемые результаты - только две записи:
1 Product_1 100.00 600.00 1
2 Product_4 500.00 1000.00 1
Любая помощь или руководство высоко ценится.
ОБНОВЛЕНИЕ: я заканчиваю тем, что использовал то, что Пратик Шарма предложил в своем комментарии, чтобы просто обернуть запрос другим SELECT WHERE [Row_Number] = 1
SELECT * FROM
(
SELECT
[ID]
,[Product_Name]
,[Price]
,SUM([Price]) OVER (PARTITION BY [ID]) AS [Price_Total]
,ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [ID]) AS [Row_Number]
FROM @SampleTable
) MultipleRows
WHERE [Row_Number] = 1
3 ответа
У вас должен быть столбец, на котором вы будете выполнять ORDER BY
за ROW_NUMBER()
, В этом случае, если вы хотите полагаться только на собственный индекс таблицы, тогда можно использовать столбец ID для ORDER BY.
Следовательно, ваш запрос правильный, и вы можете пойти с ним.
Другой вариант заключается в использовании WITH TIES
пункт. Но опять же, если вы будете использовать предложение WITH TIES со столбцом ORDER BY on ID, производительность будет очень низкой. WITH TIES
только хорошо работает, если у вас есть четко определенный индекс. И затем можно использовать этот индексированный столбец с предложением WITH TIES.
SELECT TOP 1 WITH TIES *
FROM (
SELECT [ID]
,[Product_Name]
,[Price]
,SUM([Price]) OVER (PARTITION BY [ID]) AS [Price_Total]
FROM @SampleTable
) TAB
ORDER BY ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY <IndexedColumn> DESC)
Этот запрос может помочь вам немного. Но помните, что он также не будет обеспечивать лучшую производительность, чем запрос, написанный вами. Это только сокращение строки кода.
Одним из вариантов является использование предложения WITH TIES. Нет дополнительного поля RN.
Надеюсь, у вас есть правильный порядковый номер или дата, которые можно использовать либо в sum() over
или в финале row_number() over
пример
SELECT Top 1 with ties *
From (
Select [ID]
,[Product_Name]
,[Price]
,SUM([Price]) OVER (PARTITION BY [ID]) AS [Price_Total]
FROM @SampleTable T1
) A
Order By ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [Price_Total] Desc)
Возвращает
ID Product_Name Price Price_Total
1 Product_1 100.00 600.00
2 Product_4 500.00 1000.00
Не существует "top ROW_NUMBER", если у вас нет столбца, который определяет порядок.
Если вы просто хотите произвольную строку для каждого идентификатора, вы можете использовать ниже. Чтобы детерминистически выбрать один, вам нужно сделать заказ по детерминированным уникальным критериям.
DECLARE @SampleTable TABLE
(
ID INT,
Price MONEY,
Product_Name VARCHAR(50),
INDEX cix CLUSTERED (ID)
);
INSERT INTO @SampleTable
VALUES (1,100,'Product_1'),
(1,200,'Product_2'),
(1,300,'Product_3'),
(2,500,'Product_4'),
(2,200,'Product_5'),
(2,300,'Product_6');
WITH T AS
(
SELECT *,
OrderingColumn = ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM @SampleTable
)
SELECT ID,
SUBSTRING(MIN(CONCAT(STR(OrderingColumn), Product_Name)), 11, 50) AS Product_Name,
CAST(SUBSTRING(MIN(CONCAT(STR(OrderingColumn), Price)), 11, 50) AS MONEY) AS Price,
SUM(Price) AS Price_Total
FROM T
GROUP BY ID
План для этого достаточно эффективен, поскольку он может использовать индекс, упорядоченный id
и не имеет дополнительных сортировок, катушек или проходов через стол.