2010-08-31 4 views
9

У меня есть таблица со многими идентификаторами и многими датами, связанными с каждым идентификатором, и даже несколькими идентификаторами без даты. Для каждой комбинации ID и даты я хочу выбрать идентификатор, дату и следующую самую большую дату, также связанную с этим же идентификатором, или null в качестве следующей даты, если ее не существует.SQL - выберите следующий запрос даты

Пример таблицы:

ID  Date 
1  5/1/10 
1  6/1/10 
1  7/1/10 
2  6/15/10 
3  8/15/10 
3  8/15/10 
4  4/1/10 
4  4/15/10 
4  

Желаемая Выход:

ID  Date  Next_Date 
1  5/1/10  6/1/10 
1  6/1/10  7/1/10 
1  7/1/10  
2  6/15/10  
3  8/15/10  
3  8/15/10  
4  4/1/10  4/15/10 
4  4/15/10  
+0

Какая ваша база данных – Bharat

ответ

13
SELECT 
    mytable.id, 
    mytable.date, 
    (
     SELECT 
      MIN(mytablemin.date) 
     FROM mytable AS mytablemin 
     WHERE mytablemin.date > mytable.date 
      AND mytable.id = mytablemin.id 
    ) AS NextDate 
FROM mytable 

Это было проверено на SQL Server 2008 R2 (но он должен работать на других СУБД) и производит следующий вывод:

 
id   date     NextDate 
----------- ----------------------- ----------------------- 
1   2010-05-01 00:00:00.000 2010-06-01 00:00:00.000 
1   2010-06-01 00:00:00.000 2010-06-15 00:00:00.000 
1   2010-07-01 00:00:00.000 2010-08-15 00:00:00.000 
2   2010-06-15 00:00:00.000 2010-07-01 00:00:00.000 
3   2010-08-15 00:00:00.000 NULL 
3   2010-08-15 00:00:00.000 NULL 
4   2010-04-01 00:00:00.000 2010-04-15 00:00:00.000 
4   2010-04-15 00:00:00.000 2010-05-01 00:00:00.000 
4   NULL     NULL 

Update 1: Для тех, заинтересованы, я сравнил производительность двух вариантов в SQL Server 2008 R2 (один использует агрегат MIN, а другой использует TOP 1 с ORDER BY):

Без индекса в столбце даты версия MIN имела стоимость 0,0187916, а версия TOP/ORDER BY имела стоимость 0,115073, поэтому версия MIN была «лучше».

С индексом в столбце даты они выполняются одинаково.

Обратите внимание, что это тестирование только с этими 9 записей, так что результаты могут быть (очень) поддельными ...

Update 2: Результатов справедливы для 10000 равномерно распределенных случайных записей. Запрос TOP/ORDER BY занимает так много времени, чтобы работать со 100 000 записей, которые я должен был отменить и отказаться.

+0

лучше использовать порядок, чем агрегирующие функции. Это у вас большой стол, особенно –

+0

@Andrii: Я не могу говорить для других БД, но на SQL Server это не должно меняться. Если есть индекс, он достаточно умный, чтобы знать, что он может просто прочитать первую строку; если нет индекса, он должен сканировать всю таблицу в любом случае. Фактически, с ORDER BY это может быть медленнее, поскольку для выполнения O (n * lg (n)) вместо сканирования O (n) потребуется выполнить. –

+0

Это mssql db с запросом, проходящим через доступ, что означает, что запрос LIMIT не будет работать в любом случае. Минимальный запрос выше работал отлично с небольшим добавлением добавления mytable.id = mytablemin.id в оператор WHERE. Запрос немного вялый, но в поле даты, которое я сейчас использую, нет индекса. Спасибо всем за помощь. – John

1

SELECT id, date, (SELECT date FROM table t1 WHERE t1.date > t2.date ORDER BY t1.date LIMIT 1) FROM table t2

1

Если дб оракул, вы можете использовать lead() and lag() функции.

SELECT id, date, 
LEAD(date, 1, 0) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE, 
FROM Your_table 
ORDER BY ID; 
+0

Вышеприведенный код вызывает ошибку для меня - значение 0 должно быть нулевым, поскольку оракул sql жалуется на то, что он является несовместимым типом данных (число вместо даты), нижеследующее работает нормально: SELECT id, date, LEAD (date, 1, null) OVER (PARTITION BY ID ORDER BY Date DESC NULLS LAST) NEXT_DATE, FROM Your_table – bawpie

Смежные вопросы