#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, которая соответствует этой. С ПОМОЩЬЮ СВЯЗЕЙ — правильный ответ