Как выбрать только первый ROW_NUMBER в сочетании с SUM - PullRequest
0 голосов
/ 30 июня 2018

Мне нравится группировать свою таблицу по [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

Любая помощь или руководство высоко ценится.

UPDATE: В конечном итоге я использую то, что Пратик Шарма предложил в своем комментарии, чтобы просто обернуть запрос другим 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 ]

0 голосов
/ 30 июня 2018

У вас должен быть столбец, в котором вы будете выполнять 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)

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

0 голосов
/ 30 июня 2018

Не существует "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, и не имеет дополнительных сортировок, спул или проходов через таблицу.

enter image description here

0 голосов
/ 30 июня 2018

В одном варианте используется предложение 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
...