Nerelační řešení
Nemyslím si, že žádná z dalších odpovědí je správná.
-
GROUP BY
nebude fungovat -
Pomocí
ROW_NUMBER()
vnutí data do struktury systému evidence záznamů, která je fyzická, a poté je zpracuje jako fyzické záznamy. Za obrovské náklady na výkon. K napsání takového kódu vás to samozřejmě nutí přemýšlet z hlediska RFS namísto myšlení v relačních termínech. -
Použití CTE je stejné. Iterace přes data, zejména data, která se nemění. Za trochu jiné masivní náklady.
-
Kurzory jsou rozhodně špatné z různých důvodů. (a) Kurzory vyžadují kód a vy jste požádali o zobrazení (b) Kurzory opustí jádro pro zpracování sady a vrátí se ke zpracování po řádcích. Opět není vyžadováno. Pokud vývojář v některém z mých týmů používá kurzory nebo dočasné tabulky v relační databázi (tj. nikoli v systému evidence záznamů), zastřelím je.
Relační řešení
-
Vaše data je relační, logická, dvě dané data sloupce jsou vše, co je potřeba.
-
Jistě, musíme vytvořit View (odvozený vztah), abychom získali požadovanou zprávu, ale to sestává z čistých SELECTů, což je zcela odlišné od zpracování (převedení na soubor , což je fyzické, a následné zpracování souboru; nebo dočasné tabulky; nebo pracovní stoly; nebo CTE; nebo Číslo_ŘÁDKU(); atd).
-
Na rozdíl od lamentací "teoretiků", kteří mají agendu, SQL zvládá Relační data naprosto dobře. A vaše data jsou relační.
Udržujte proto relační myšlení, relační pohled na data a mentalitu zpracování souborů. Každý požadavek na sestavu přes relační databázi lze splnit pomocí jediného SELECT. Není třeba se vracet k metodám zpracování souborů ISAM před rokem 1970.
Budu předpokládat, že primární klíč (soubor sloupců, které poskytují relační jedinečnost řádku) je Date,
a na základě uvedených příkladů dat je datový typ DATE.
Zkuste toto:
CREATE VIEW MyTable_Base_V -- Foundation View
AS
SELECT Date,
Date_Next,
Price
FROM (
-- Derived Table: project rows with what we need
SELECT Date,
[Date_Next] = DATEADD( DD, 1, O.Date ),
Price,
[Price_Next] = (
SELECT Price -- NULL if not exists
FROM MyTable
WHERE Date = DATEADD( DD, 1, O.Date )
)
FROM MyTable MT
) AS X
WHERE Price != Price_Next -- exclude unchanging rows
GO
CREATE VIEW MyTable_V -- Requested View
AS
SELECT [Date_From] = (
-- Date of the previous row
SELECT MAX( Date_Next ) -- previous row
FROM MyTable_V
WHERE Date_Next < MT.Date
),
[Date_To] = Date, -- this row
Price
FROM MyTable_Base_V MT
GO
SELECT *
FROM MyTable_V
GO
Metoda, obecná
Samozřejmě se jedná o metodu, proto je obecná, lze ji použít k určení From_
a To_
libovolného rozsahu dat (zde Date
rozsah), na základě jakékoli změny dat (zde změna Price
).
Zde jsou vaše Dates
jsou po sobě jdoucí, takže určení Date_Next
je jednoduché:zvyšte Date
o 1 den. Pokud se PK zvyšuje, ale ne po sobě jdoucích (např. DateTime
nebo TimeStamp
nebo nějaký jiný klíč), změňte odvozenou tabulku X
komu:
-- Derived Table: project rows with what we need
SELECT DateTime,
[DateTime_Next] = (
-- first row > this row
SELECT TOP 1
DateTime -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
),
Price,
[Price_Next] = (
-- first row > this row
SELECT TOP 1
Price -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
)
FROM MyTable MT
Užijte si to.
Prosím, neváhejte komentovat, klást otázky atd.