Подкачка окна SQL Server на основе количества групп

#sql-server #azure-sql-database

#sql-сервер #azure-sql-database

Вопрос:

Учитывая следующую структуру таблицы

Столбец
ID
Имя
Дата создана

со следующими данными

ID Имя Дата создана
1 Джо 1/13/2021
2 Фред 1/13/2021
3 Боб 1/12/2021
4 Подать в суд 1/12/2021
5 Салли 1/10/2021
6 Алекс 1/9/2021

Мне нужен SQL, который будет перелистывать данные на основе datecreated. Запрос должен возвращать верхние 3 записи и любую запись, которая также имеет общую дату, созданную для верхних 3.

Итак, приведите приведенные выше данные, мы должны вернуть Joe, Fred и Bob (в качестве 3 лучших записей) плюс Sue, поскольку у sue та же дата, что и у Bob.

Есть ли что-то вроде ROW_NUMBER, которое увеличивается для каждой строки, где встречается другое значение.

В некотором контексте этот запрос используется для создания представления типа повестки дня, и как только мы выбираем любую дату, мы хотим сохранить все данные для этой даты вместе.

РЕДАКТИРОВАТЬ У меня есть решение, но оно пахнет:

 ;WITH CTE AS ( SELECT ROW_NUMBER() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable),
        PAGE AS (SELECT * 
                  FROM CTE
                  WHERE RowNum<=5)

SELECT * 
FROM Page
UNION
SELECT * 
FROM CTE 
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)
                    
 

Комментарии:

1. Хм, таблицы отображаются нормально в режиме предварительного просмотра в режиме редактирования, но не здесь…

2. Своего рода комбинация ROW_NUMBER и DENSE_RANK , последняя будет меняться только при отдельных изменениях, но в этом случае вы получите первые 5 строк

Ответ №1:

Я использовал TOP 3 WITH TIES пример и ROW_NUMBER пример и CTE для возврата четырех записей:

 DROP TABLE IF EXISTS #tmp
GO
CREATE TABLE #tmp (
    Id          INT PRIMARY KEY,
    name        VARCHAR(20) NOT NULL,
    dateCreated DATE
)
GO

INSERT INTO #tmp VALUES
    ( 1, 'Joe', '13 Jan 2021' ),
    ( 2, 'Fred', '13 Jan 2021' ),
    ( 3, 'Bob', '12 Jan 2021' ),
    ( 4, 'Sue', '12 Jan 2021' ),
    ( 5, 'Sally', '10 Jan 2021' ),
    ( 6, 'Alex', '9 Jan 2021' )
GO

-- Gets same result
SELECT TOP 3 WITH TIES *
FROM #tmp t
ORDER BY dateCreated DESC 


;WITH cte AS (
SELECT ROW_NUMBER() OVER( ORDER BY dateCreated DESC ) rn, *
FROM #tmp
)
SELECT *
FROM #tmp t
WHERE EXISTS
(
    SELECT *
    FROM cte c
    WHERE rn <=3
      AND t.dateCreated = c.dateCreated
)
 

Мои результаты:

Результаты

Комментарии:

1. спасибо, это выглядит немного чище, чем то, что я получил. Любопытно увидеть различия в плане выполнения

2. Я добавил TOP 3 WITH TIES пример, который представляет собой гораздо более простой код, но функционально может не делать то, что вы хотите. Я имею в виду, что это работает для ваших данных, но может не подходить для более сложных примеров.

3. да, позвольте мне посмотреть, работает ли if WITH ties с моим запросом, который определенно сложнее, чем мой пример;-)

4. Да, С галстуками — вот способ сделать это! Спасибо

Ответ №2:

Как @Charlieface, нам нужно только заменить ROW_NUMBER на DENSE_RANK . Так что ROW_NUMBER будет привязан к одному и тому же значению.

Когда мы запускаем запрос:

 SELECT DENSE_RANK ()  OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable
 

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

Таким образом, в результате мы можем задать RowNum<=3 в запросе, чтобы получить 3 лучших:

 ;WITH CTE AS ( SELECT DENSE_RANK() OVER(ORDER BY DateCreated DESC) RowNum,CAST(DateCreated AS DATE) DateCreated,Name
                FROM MyTable),
        PAGE AS (SELECT * 
                  FROM CTE
                  WHERE RowNum<=3)

SELECT * 
FROM Page
UNION
SELECT * 
FROM CTE 
WHERE DateCreated=(SELECT MIN(DateCreated) FROM Page)
 

Первый — как ваш, второй — как указано выше. Результаты двух запросов одинаковы.
введите описание изображения здесь

Пожалуйста, дайте нам знать, если вам понадобится дополнительная информация.

Комментарии:

1. Это на самом деле возвращает слишком много данных, так как вы извлекаете первые 3 группы DateCreated, мы хотим получить первые 3 результата, а затем любую другую datecreated, которая соответствует этой. С ПОМОЩЬЮ СВЯЗЕЙ — правильный ответ