#sql #sql-server #tsql #sql-server-2008 #select
Вопрос:
У меня есть таблица со столбцами Name и Date. Я хочу получить самую раннюю дату появления текущего имени. Например:
Имя | Дата |
---|---|
X | 30 января-2021 |
X | 29 января-2021 |
X | 28 января-2021 |
Y | 27 января-2021 |
Y | 26 января-2021 |
Y | 25 января-2021 |
Y | 24 января-2021 |
X | 23 января-2021 |
X | 22 января-2021 |
Теперь, когда я пытаюсь получить самую раннюю дату, когда начало появляться текущее имя (X), я хочу получить 28 января, но sql-запрос выдаст 22 января 2021 года, потому что именно тогда X появился изначально в первый раз.
Обновление: это был запрос, который я использовал:
Select min(Date) from myTable where Name='X'
Я использую более старый SQL Server 2008 (в процессе обновления), поэтому у меня нет доступа к функциям ОПЕРЕЖЕНИЯ / ЗАДЕРЖКИ.
Предлагаемые ниже решения работают так, как предполагалось. Спасибо.
Комментарии:
1. Вы случайно имеете в виду: вам нужна самая ранняя дата последней группы строк с одинаковым
Name
значением?2. Вам необходимо предоставить всю соответствующую информацию, такую как первичный ключ вашей таблицы (предположительно, он у вас есть), поскольку, как отмечалось, предоставленного вами недостаточно для поддержки требования.
Ответ №1:
Это тип проблемы пробелов и островов.
Существует много решений. Вот тот, который оптимизирован для вашего случая
- Используется
LEAD/LAG
для определения первой строки в каждой группе - Фильтровать только эти строки
- Пронумеруйте их строками и возьмите первую
WITH StartPoints AS (
SELECT *,
IsStart = CASE WHEN Name <> LEAD(Name, 1, '') OVER (ORDER BY Date DESC) THEN 1 END
FROM YourTable
),
Numbered AS (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
FROM StartPoints
WHERE IsStart = 1 AND Name = 'X'
)
SELECT
Name, Date
FROM Numbered
WHERE rn = 1;
Для SQL Server 2008 или более ранней версии (с которой я настоятельно рекомендую вам обновиться), вы можете использовать самосоединение с нумерацией строк для имитации LEAD/LAG
WITH RowNumbered AS (
SELECT *,
AllRn = ROW_NUMBER() OVER (ORDER BY Date ASC)
FROM YourTable
),
StartPoints AS (
SELECT r1.*,
IsStart = CASE WHEN r1.Name <> ISNULL(r2.Name, '') THEN 1 END
FROM RowNumbered r1
LEFT JOIN RowNumbered r2 ON r2.AllRn = r1.AllRn - 1
),
Numbered AS (
SELECT *,
rn = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date DESC)
FROM StartPoints
WHERE IsStart = 1
)
SELECT
Name, Date
FROM Numbered
WHERE rn = 1;
Комментарии:
1. Спасибо, но моя версия sql пока не поддерживает функции ОПЕРЕЖЕНИЯ / ЗАДЕРЖКИ. Что-нибудь без них?
2. @goodsamaritan это будет означать, что вы используете полностью неподдерживаемую версию SQL Server. Предполагается , что когда вы задаете вопрос, вы используете поддерживаемое программное обеспечение, и если это не так, вам нужно сообщить об этом пользователям (обычно путем пометки версии). Если у вас нет доступа к
LEAD
/LAG
вы используете SQL Server 2008 или более раннюю версию; как это было добавлено в SQL server 2012 (у которого осталось около 9 месяцев расширенной поддержки). 2008 полностью не поддерживается более 2 лет, а предыдущие версии намного дольше. Давно пора отсортировать этот путь обновления.3. Здесь вы можете смоделировать это с помощью самосоединения
Ответ №2:
Это проблема пробелов и островков. На основе выборочных данных это будет работать:
WITH Groups AS(
SELECT YT.[Name],
YT.[Date],
ROW_NUMBER() OVER (ORDER BY YT.Date DESC) -
ROW_NUMBER() OVER (PARTITION BY YT.[Name] ORDER BY Date DESC) AS Grp
FROM dbo.YourTable YT),
FirstGroup AS(
SELECT TOP (1) WITH TIES
G.[Name],
G.[Date]
FROM Groups G
WHERE [Name] = 'X'
ORDER BY Grp ASC)
SELECT MIN(FG.[Date]) AS Mi
Ответ №3:
Если я правильно понял, вы хотите знать, когда X исчез и снова появился. в этом случае вы можете искать пробелы в датах по группам.
это и пример того, как это обнаружить
SELECT name
,DATE
FROM (
SELECT *
,DATEDIFF(day, lead(DATE) OVER (
PARTITION BY name ORDER BY DATE DESC
), DATE) DIF
FROM YourTable
) a
WHERE DIF > 1