2017-05-17 13 views
3

私は日付の列を含むテーブルを持っています。SQL:行ごとに次の日付値を取得

ID |  Date 
----|----------- 
    1 | 2000-01-01 
    2 | 2000-02-01 
    3 | 2000-02-01 
    4 | 2000-03-01 

Iは、現在の日付よりも大きい場合、各行、ID、日付及び(テーブル内のすべての日付の)最小の日付を返し、その選択を必要とします。

ID |  Date | Next date 
----+------------+------------ 
    1 | 2000-01-01 | 2000-02-01 
    2 | 2000-02-01 | 2000-03-01 
    3 | 2000-02-01 | 2000-03-01 
    4 | 2000-03-01 |  (NULL) 

私の最初のアプローチの列DATEの値が一意である場合、

SELECT id, date, LEAD (date, 1) OVER (ORDER BY date NULLS LAST) AS next_date 
    FROM t 

しかし、これだけ作品でした。

アイデア?

+0

a.date> b.dateというクエリでグループに参加し、bで最初に見つかったレコードのみを使用しますか? – nabuchodonossor

答えて

6

windowing clauseの解析関数を使用できます。あなたがmin()またはfirst_value()のように行いますいずれかを使用する必要があるのでlead()は、ウィンドウ句をサポートしていません:

FIRST_VALUE ("Date") 
    OVER (ORDER BY "Date" RANGE BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) 

をデフォルトのウィンドウ句は、すべての行に2000-01-01の同じ値を与え、ROWSを使用してしまうRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW、ありますウィンドウはlead()の重複した日付で実行されます(ID2はまだ2000-02-01を取得し、1 FOLLOWINGではなくROWS BETWEEN CURRENT ROW...を使用した場合、ID 4はnullではなく2000-03-01になります)。この範囲を使用

デモ:日付の値が現在の行よりも高い

with t (ID, "Date") as (
    select 1, date '2000-01-01' from dual 
    union all select 2, date '2000-02-01' from dual 
    union all select 3, date '2000-02-01' from dual 
    union all select 4, date '2000-03-01' from dual 
) 
select id, "Date", FIRST_VALUE ("Date") OVER (ORDER BY "Date" 
    RANGE BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) AS next_date 
FROM t; 

     ID Date  NEXT_DATE 
---------- ---------- ---------- 
     1 2000-01-01 2000-02-01 
     2 2000-02-01 2000-03-01 
     3 2000-02-01 2000-03-01 
     4 2000-03-01   

行のみが考慮されます。そして、これはまだ一度テーブルにヒットするだけです。

dateは予約語なので"Date"を二重引用符で囲みましたが、サンプルデータから引用符付きの識別子のように見えますが、クエリでは引用符で囲まれていないため、名前は本当に...)

+0

ベスト答え。 –

+0

私はそれを好きです:-) –

+0

非常に良い答えですが、私の場合は、あなたのコードは正常に動作していますある顧客のために、私はすべての顧客のために私のクエリを実行すると、彼は私に開始日と同じ終了日を返します。 あなたはwhats kind problemと言うことができますか?...私は以下のクエリを提供します: –

1

の別名の日付とその直前のリード値を含むCTEを作成する方法があります。次に、最終的な結果を得るために、このCTEを日付の元の表に追加します。上記のコード

WITH cte AS (
    SELECT t.date, 
      LEAD(t.date, 1) OVER (ORDER BY t.date NULLS LAST) AS next_date 
    FROM (SELECT DISTINCT date FROM yourTable) t 
) 
SELECT 
    t1.ID, 
    t1.date, 
    t2.next_date 
FROM yourTable t1 
INNER JOIN cte t2 
    ON t1.date = t2.date 
+0

それは動作します。私はそれが大きなテーブルでどのように実行されるかを確認する必要があります。正直言って、あまり複雑ではないソリューションがあることを期待していました。 :-) とにかくありがとう。 –

+0

@ D.Mika upvoteは可能ですか? –

+0

このソリューションは実際には比較的複雑ではありません。唯一のトリックは、あなたの重複した日付を回避するために 'DISTINCT'を使用しています。 –

4
select * , (select min(t2.date) from table t2 where t2.date > t1.date) 
from Table t1 

は自分の質問に答えるために、SQL Server

+1

これは、Oracleで有効にするには(予約語 'table'と' date'の使用を無視して)、他の式があれば '*'にテーブルの別名を付けなければなりません。 'select t1。*、選択... ' –

1

です。 ;-)(ちょうどこのポストを越えつまずく人に別のオプションを表示するために)

別の解決策は、副選択を使用することになります。ここでは

0

は「明確な」せずに、別のアプローチである:

select 
    ted.id, 
    ted.date_col, 
    (select 
    min(ted2.date_col) 
    from 
    test_date_v ted2 
    where 
    ted2.id != ted.id and 
    ted2.date_col > ted.date_col) next_date_col 
from 
    test_date_v ted; 
+0

私はそれがあなた自身でスローすると思った。良い仕事! – Ychdziu

関連する問題