2017-01-03 6 views
1

Я ищу способ получить самое нижнее следующее значение в последовательности. В принципе, у меня есть набор данных Даты, и я хочу, чтобы он вернулся на следующий день, если это не последняя дата в базе данных, а затем я хочу, чтобы она вернула это вместо этого.Имейте столбец с наименьшим возможным следующим значением (самосоединение таблицы)

Мой текущий запрос выглядит, как это и почти работает - конечно до точки, где я хочу последнюю возможное значение вместо следующего:

SELECT 
    a.date, 
    a.key, 
    a.description, 
    b.date NextDate 
FROM 
    my_table a 
    CROSS APPLY (SELECT TOP 1 
    b.date 
FROM 
    my_table b 
WHERE 
    a.key = b.key AND 
    a.date < b.date) b 

Sample данные:

+----------+-----+-------------+ 
| date | key | description | 
+----------+-----+-------------+ 
| 20170101 | atx | xxx   | 
| 20161228 | hfn | xxx   | 
| 20161222 | ktn | xxx   | 
| 20161214 | yqe | xxx   | 
| 20161204 | olp | xxx   | 
| 20161122 | bux | xxx   | 
+----------+-----+-------------+ 

Каким должен быть результат:

+----------+-----+-------------+----------+ 
| date | key | description | NextDate | 
+----------+-----+-------------+----------+ 
| 20170101 | atx | xxx   | 20170101 | 
| 20161228 | hfn | xxx   | 20170101 | 
| 20161222 | ktn | xxx   | 20161228 | 
| 20161214 | yqe | xxx   | 20161222 | 
| 20161204 | olp | xxx   | 20161214 | 
| 20161122 | bux | xxx   | 20161204 | 
+----------+-----+-------------+----------+ 
+0

Вы забыли предложение 'ORDER BY' в' CROSS APPLY 'запрос. – DVT

+0

Какая версия сервера sql, которую вы используете –

+0

, лучше указала ее до 2014 года. – Spurious

ответ

1

Вы можете использовать выражение case для сделай это.

SELECT 
    a.date, 
    a.key, 
    a.description, 
    case when date = max(a.date) over() then date 
    else (select min(date) from mytable b where a.date < b.date) end as NextDate 
FROM 
    my_table a 
+0

Возможно, это был мой плохой выбор данных, но данные в большинстве случаев не строго хронологические. Я исправляю свои данные. – Spurious

+0

обязательно ... редактируйте. –

+0

Нет, потому что 'GetDate()' возвращает текущую дату. Я изменил свои данные, чтобы лучше отразить то, что мне нужно. – Spurious

0

Вы можете использовать lag на дату колонке

select t.*, 
    lag(date, 1, date) over (order by date desc) nextdate 
from 
(SELECT 
    a.date, 
    a.key, 
    a.description, 
    b.date NextDate 
FROM 
    my_table a 
    CROSS APPLY (SELECT TOP 1 
    b.date 
FROM 
    my_table b 
WHERE 
    a.key = b.key AND 
    a.date < b.date) b) t 
0

Я считаю, что вы хотите:

select a.*, 
     coalesce(lead(date) over (order by date), 
       max(date) over() 
       ) 
from my_table a; 
+0

Это просто дает мне ту же дату для каждого столбца. – Spurious

+0

@Spurious. , , Это не должно указывать на одну и ту же дату для каждого столбца. Он должен иметь следующую дату, если есть одна и максимальная дата, если их нет. –

0

Попробуйте

;with cte as 
(
SELECT [DATE] = Cast([date] AS DATE), 
     [key], 
     [description], 
     Lag([date])OVER(ORDER BY Cast([date] AS DATE) DESC) AS prev_date 
FROM (VALUES ('20170101','atx','xxx'), 
       ('20161228','hfn','xxx'), 
       ('20161222','ktn','xxx'), 
       ('20161214','yqe','xxx'), 
       ('20161204','olp','xxx'), 
       ('20161122','bux','xxx')) tc ([date], [key], [description]) 
) 
SELECT [date], 
     [Key], 
     [Description], 
     NextDate = Iif([date] < prev_date, prev_date, [date]) 
FROM cte 

Результат:

+------------+-----+-------------+------------+ 
| date | Key | Description | NextDate | 
+------------+-----+-------------+------------+ 
| 2017-01-01 | atx | xxx   | 2017-01-01 | 
| 2016-12-28 | hfn | xxx   | 2017-01-01 | 
| 2016-12-22 | ktn | xxx   | 2016-12-28 | 
| 2016-12-14 | yqe | xxx   | 2016-12-22 | 
| 2016-12-04 | olp | xxx   | 2016-12-14 | 
| 2016-11-22 | bux | xxx   | 2016-12-04 | 
+------------+-----+-------------+------------+ 
0

Если в вашей таблице никогда не было недостающей даты, работа над ней будет следующей.

SELECT CONVERT(DATE,CONVERT(CHAR(10),a.date,120)) 
,a.key, 
,a.description, 
,CASE 
    WHEN (SELECT MAX(a.date) FROM my_table a) <> AsAtDateID 
     THEN DATEADD(DAY,1,CONVERT(DATE,CONVERT(CHAR(10),a.date,120)))--This could be a select statement 
    ELSE CONVERT(DATE,CONVERT(CHAR(10),a.date,120)) 
END 
FROM my_table a 
ORDER BY Date DESC 

В противном случае, если отсутствуют даты, вы можете использовать оператор SQL в CASE для получения следующей наивысшей даты.

SELECT MIN(Date) FROM my_table WHERE Date > a.Date 

Не самый эффективный код, но, видя, что мы говорим о таблицах дат, он сработает. Я уверен, что CTE также может быть использован для этого, если вам нужно немного больше производительности. Использование SQL 2008 без LEAD & LAG и т. Д.