[MsSql] Sprawdzanie wartości kolejnym w wierszu

Cześć

 

Nawet nie wiem jak nazwać ten temat. Mam takie dane:

 

ID   Data

1

1

1

2

2

2

2

3

3

3

2

2

2

3

3

3

1

1

1

 

Daty specjalnie nie uzupełniam. Te wiersze są posortowane po dacie. Teraz chciałbym w jakiś sposób wyciągnąć takie info:

ID1   ID2    Różnica czasu

1      2        Różnica między ostatnim wierszem o ID 1 a pierwszym o ID 2.

2      3        Różnica między ostatnim wierszem o ID 2 a pierwszym o ID 3.

3      2        Różnica między ostatnim wierszem o ID 3 a pierwszym o ID 2.

2      3        Różnica między ostatnim wierszem o ID 2 a pierwszym o ID 3.

3      1        Różnica między ostatnim wierszem o ID 3 a pierwszym o ID 1.

 

W excelu to nie jest problem to zrobić ale danych w bazie może być dużo, nie chciałbym tego eksportować i dopiero obrabiać. Miał ktoś kiedyś podobny problem ?

Myśle że bez unikalnego ID może to być na prawdę bardzo trudne

Teraz to już można powiedzieć, że jest musztarda po obiedzie. Ja zmieniłbym sam system, bo nawet jak ktoś wpadnie na cudowne one query solution, to podejrzewam, że z punktu widzenia DB, to będzie miazga wydajnościowa.

Zmienna tabelaryczna na wynik całej operacji + kursor do przejścia po wierszach.

Zadnych kursorów, to można załatwić zwykłym zapytaniem.

Oczywiście jak pisali u ciebie ID to nie ID a klucz obcy (ID musi być unikalne).

 

Wiec zapytanie bym zaproponowal takie (w komentarzu masz podane tworzenie tabeli):

/*

–DROP TABLE #TB1
CREATE TABLE #TB1 (
ID INT,
DATA DATETIME
);

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 2,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 3,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();

WAITFOR DELAY ‘00:00:01’;

INSERT INTO #TB1
SELECT 1,
GETDATE();
*/
DECLARE @ID_MAX INT;

SELECT @ID_MAX = MAX(ID)
FROM #TB1;

WITH DATES_MAX
AS (
SELECT ID,
MAX(DATA) AS T_MAX
FROM #TB1 T1
GROUP BY ID
),
DATES_MIN
AS (
SELECT ID,
MIN(DATA) AS T_MIN
FROM #TB1 T1
GROUP BY ID
)
SELECT T1.ID,
T2.ID,
T1.T_MAX - T2.T_MIN
FROM DATES_MAX T1
JOIN DATES_MIN T2 ON T1.ID = CASE T2.ID
WHEN @ID_MAX
THEN 1
ELSE T2.ID + 1
END

Co do tej bazy niestety nie ma żadnych praw zapisu :wink: zwykły select zostaje. Póki co robię to w ten sposób że wyciągam wszystko, excel, nowa kolumna "czy się zmieniła wartość, i druga kolumna jeśli się zmieniła to oblicz różnicę. Następnie filtruje. Na szczęście to jest robota raz kiedyś, może nawet raz na parę miesięcy więc przeżyję.

 

No to przeciez to co ja podalem to jest zwykly select bez zapisu.

Nie jestem ekspertem, ale jak przetworzyć dane sekwencyjnie nie używając kursora? Twój kod jest eweidentnie zły, bo zwraca 3 rekordy, a powinien zwrócić 5. Tu przecież nie chodzi o globalny max i min dla danego ID, lecz o rożnicę między dwoma kolejnymi rekordami różniącymi się ID przy danym kierunku sortowania.

 

A rzeczywiście za mało rekordów, zamiast joina trzeba cross joina zrobić i będzie ok.

SQL przetwarza całe tabele więc podejście z pętlą for each jest w gigantycznej ilości przypadków nieprawidłowe i powoduje spadek wydajności zapytania więc należy kursora unikać jak ognia (chociaż czasem oczywiście się z niego korzysta).

A mógłbyś pokazać jak dokładnie to zrobić? Bo dopisanie “cross” nie wystarczy.

Zdaję sobie sprawę z wad kursorów, z drugiej strony pętle są zrozumiałe dla każdego, zaś działanie SQL niekoniecznie, to bardzo trudny język.