Te dwa zapytania opierają się na założeniu, że Taco_value
zawsze rośnie w czasie.
;WITH x AS
(
SELECT Taco_ID, Taco_date,
dr = ROW_NUMBER() OVER (PARTITION BY Taco_ID, Taco_Value ORDER BY Taco_date),
qr = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date)
FROM dbo.Taco
), y AS
(
SELECT Taco_ID, Taco_date,
rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID, dr ORDER BY qr DESC)
FROM x WHERE dr = 1
)
SELECT Taco_ID, Taco_date
FROM y
WHERE rn = 1;
Alternatywa z mniejszym szaleństwem funkcji okna:
;WITH x AS
(
SELECT Taco_ID, Taco_value, Taco_date = MIN(Taco_date)
FROM dbo.Taco
GROUP BY Taco_ID, Taco_value
), y AS
(
SELECT Taco_ID, Taco_date,
rn = ROW_NUMBER() OVER (PARTITION BY Taco_ID ORDER BY Taco_date DESC)
FROM x
)
SELECT Taco_ID, Taco_date FROM y WHERE rn = 1;
Przykłady w SQLfiddle
Aktualizacja
Dla tych, którzy śledzili, istniała spór o to, co się stanie, jeśli Taco_value
kiedykolwiek się powtórzy. Jeśli może on przejść z 1 do 2, a następnie z powrotem do 1 dla dowolnego Taco_ID
, zapytania nie będą działać. Oto rozwiązanie tego przypadku, nawet jeśli nie jest to technika z lukami i wyspami, którą ktoś taki jak Itzik Ben-Gan może wymarzyć, a nawet jeśli nie ma to znaczenia dla scenariusza PO - może to być dotyczy przyszłego czytelnika. Jest trochę bardziej skomplikowany, a także dodałem dodatkową zmienną - taką Taco_ID
, która ma tylko jedną Taco_value
.
Jeśli chcesz dołączyć pierwszy wiersz dla dowolnego identyfikatora, w którym wartość w ogóle nie zmieniła się w całym zestawie:
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER
(PARTITION BY Taco_ID ORDER BY Taco_date DESC)
FROM dbo.Taco
), rest AS (SELECT * FROM x WHERE rn > 1)
SELECT
main.Taco_ID,
Taco_date = MIN(CASE
WHEN main.Taco_value = rest.Taco_value
THEN rest.Taco_date ELSE main.Taco_date
END)
FROM x AS main LEFT OUTER JOIN rest
ON main.Taco_ID = rest.Taco_ID AND rest.rn > 1
WHERE main.rn = 1
AND NOT EXISTS
(
SELECT 1 FROM rest AS rest2
WHERE Taco_ID = rest.Taco_ID
AND rn < rest.rn
AND Taco_value <> rest.Taco_value
)
GROUP BY main.Taco_ID;
Jeśli chcesz wykluczyć te wiersze, jest to nieco bardziej złożone, ale wciąż niewielkie zmiany:
;WITH x AS
(
SELECT *, rn = ROW_NUMBER() OVER
(PARTITION BY Taco_ID ORDER BY Taco_date DESC)
FROM dbo.Taco
), rest AS (SELECT * FROM x WHERE rn > 1)
SELECT
main.Taco_ID,
Taco_date = MIN(
CASE
WHEN main.Taco_value = rest.Taco_value
THEN rest.Taco_date ELSE main.Taco_date
END)
FROM x AS main INNER JOIN rest -- ***** change this to INNER JOIN *****
ON main.Taco_ID = rest.Taco_ID AND rest.rn > 1
WHERE main.rn = 1
AND NOT EXISTS
(
SELECT 1 FROM rest AS rest2
WHERE Taco_ID = rest.Taco_ID
AND rn < rest.rn
AND Taco_value <> rest.Taco_value
)
AND EXISTS -- ***** add this EXISTS clause *****
(
SELECT 1 FROM rest AS rest2
WHERE Taco_ID = rest.Taco_ID
AND Taco_value <> rest.Taco_value
)
GROUP BY main.Taco_ID;
Zaktualizowano przykłady SQLfiddle
taco
że nie ma to nic wspólnego z jedzeniem?