ROW_NUMBER i podzapytanie

0

Witam,

podpowiedzcie pls bo coś gdzieś mi dzwoni ale coś nie mogę dojść do brzegu.

Generalnie chcę zrobić pewną operację w 1 zapytaniu zamiast rozbijać na kilka części. Mamy tabelę i dane np.:


CREATE TABLE KodWaznosc(
           Kod Char(3),
           DataStart DateTime,
           poleJakies char(5)
           )
 
           INSERT INTO KodWaznosc (Kod, DataStart, poleJakies) VALUES (111,'2017-01-01','opis')
           INSERT INTO KodWaznosc (Kod, DataStart, poleJakies) VALUES (111,'2017-02-02','opis')
           INSERT INTO KodWaznosc (Kod, DataStart, poleJakies) VALUES (111,'2017-03-03','opis')
           INSERT INTO KodWaznosc (Kod, DataStart, poleJakies) VALUES (212,'2017-01-11','opis')
           INSERT INTO KodWaznosc (Kod, DataStart, poleJakies) VALUES (212,'2017-04-15','opis')

Teraz chciałbym napisać zapytanie którego wynikiem będzie wiersz jak jest + data z wiersza następującego dla tego kodu (taka DataKoniec), np:

Kod DataStart DataKoniec
111 2017-01-01 0000.000 2017-02-02 0000.000
111 2017-02-02 0000.000 2017-03-03 0000.000
111 2017-03-03 0000.000 NULL
212 2017-01-11 0000.000 2017-04-15 0000.000
212 2017-04-15 0000.000 NULL

By to osiągnąć używam ROW_Number i później łącze ID z ID+1 . I teraz chciałbym to zrobić w 1 zapytaniu ale ciągle mi coś nie do końca działa. Przykładowe zapytanie któryn próbowałem to osiągnąć:

  	SELECT ROW_NUMBER() OVER (PARTITION BY frst.Kod ORDER BY frst.Kod, frst.[DataStart] ASC) as PosNo,
		 frst.Kod
		  ,frst.[DataStart]
		  ,nxt.[DataStart] as DataKoniec
	  FROM [KodWaznosc] as frst
	   INNER JOIN(
			--podzapytanie
			  Select ROW_NUMBER() OVER (PARTITION BY Kod ORDER BY Kod, [DataStart] ASC)+1 as PosNOnext, Kod,[DataStart]
			  FROM [KodWaznosc]) nxt on 
	  [frst].Kod = [nxt].Kod
	  and 
	  [frst].PosNo = nxt.PosNOnext

Mam wrażenie, że gdzieś robię czeski błąd ;/ ... Widzicie gdzie ? Względnie jakieś inne optymalne rozwiązanie mojego problemu ?

1

Mam wrażenie, że gdzieś robię czeski błąd ;/ ... Widzicie gdzie ? Względnie jakieś inne optymalne rozwiązanie mojego problemu ?

Wybacz, właśnie się budzę i nie mam sił, ale zrobiłbym to tak:

 with frst AS (
	SELECT	ROW_NUMBER() OVER (PARTITION BY Kod ORDER BY Kod, [DataStart] ASC) AS PosNo,
			Kod,
			[DataStart]
	FROM [KodWaznosc]
), nxt AS (
	SELECT	ROW_NUMBER() OVER (PARTITION BY Kod ORDER BY Kod, [DataStart] ASC) + 1 AS PosNOnext,
			Kod,
			[DataStart]
	FROM [KodWaznosc]
)

SELECT	frst.PosNo,
		frst.KOD,
		frst.[DataStart],
		nxt.[DataStart] AS DataKoniec
FROM frst INNER JOIN nxt ON [frst].Kod = [nxt].Kod AND [frst].PosNo = nxt.PosNOnext
1

Użyć ROW_NUMBER?! W żadnym wypadku! ...a komu to potrzebne, a dlaczego?

SELECT * 
FROM KodWaznosc K
LEFT OUTER JOIN	KodWaznosc KW ON 
	KW.Kod = K.Kod
	AND KW.DataStart = (SELECT MIN(DataStart)
						FROM KodWaznosc
						WHERE Kod = K.Kod
							AND DataStart > K.DataStart)
0

Genialne @Haskell ... znowu potwierdza się powiedzenie, że najprostsze rozwiązania są najlepsze, w ogóle jakoś nie poszedłem tą drogą. Wielkie dzięki!

@Dziadu za Twoje rozwiązanie też dzięki działa fajnie ... przy czym ja już w swoim wstępnym kodzie zrobiłem mały błąd logiczny także i on powielony u Ciebie (nic co nie dało by się poprawić pewnie ;) ).

1

Jeżeli to SQL >= 2012 to uzyj lead (https://msdn.microsoft.com/pl-pl/library/hh213125(v=sql.110).aspx)
Funkcja dodana aby unikać self-joinów

SELECT  
     KOD,
     [DataStart],
     LEAD (DataStart, 1) OVER  (PARTITION BY Kod ORDER BY [DataStart])  AS DataKoniec
FROM 
    [KodWaznosc]
0

Ok zatem dla Troszkę ponad 5 milionów rekordów zapytanie @Haskell wykonuje się w 5,06 minuty, natomiast zapytanie @Panczo w 1,02 minuty ;) Wyniki są identyczne.

Także @Panczo wielkie dzięki Twoja podpowiedź i ta nowa funkcja jest świetna zarówno pod względem przejrzystości kodu jak i optymalizacji! Fajnie poznać coś nowego ;]

1 użytkowników online, w tym zalogowanych: 0, gości: 1