Rozwiązanie nierelacyjne
Nie sądzę, aby inne odpowiedzi były poprawne.
-
GROUP BY
nie zadziała -
Korzystanie z
ROW_NUMBER()
zmusza dane do struktury Record Filing System, która jest fizyczna, a następnie przetwarza je jako fizyczne rekordy. Przy ogromnych kosztach wydajności. Oczywiście pisanie takiego kodu zmusza cię do pomyślenia w kategoriach RFS zamiast myśleć w kategoriach relacyjnych. -
Korzystanie z CTE jest takie samo. Iteracja po danych, zwłaszcza danych, które się nie zmieniają. Przy nieco innych ogromnych kosztach.
-
Kursory są zdecydowanie niewłaściwą rzeczą z różnych powodów. (a) Kursory wymagają kodu, a użytkownik zażądał widoku (b) Kursory porzucają silnik przetwarzania zestawów i powracają do przetwarzania wiersz po wierszu. Znowu nie jest wymagane. Jeśli programista w którymkolwiek z moich zespołów używa kursorów lub tabel tymczasowych w relacyjnej bazie danych (tj. nie w systemie archiwizacji rekordów), strzelam do nich.
Rozwiązanie relacyjne
-
Twoje dane jest relacyjne, logiczne, te dwa podane dane kolumny to wszystko, co jest potrzebne.
-
Oczywiście, aby uzyskać żądany raport, musimy utworzyć widok (relację pochodną), ale składa się on z samych SELECTów, co jest zupełnie inne niż przetwarzanie (konwertowanie go do pliku , który jest fizyczny, a następnie przetwarza plik; lub tabele tymczasowe; lub stoły robocze; lub CTE; lub ROW_Numer(); itp).
-
Wbrew lamentom „teoretyków”, którzy mają agendę, SQL doskonale radzi sobie z danymi relacyjnymi. A Twoje dane są relacyjne.
Dlatego utrzymuj relacyjny sposób myślenia, relacyjny pogląd na dane i mentalność przetwarzania zbiorów. Każde wymaganie dotyczące raportu w relacyjnej bazie danych można spełnić za pomocą pojedynczego SELECT. Nie ma potrzeby cofania się do metod obsługi plików ISAM sprzed 1970 r.
Przyjmę, że klucz podstawowy (zestaw kolumn, które dają relacyjną unikatowość wiersza) to Date,
i na podstawie podanych przykładowych danych typ danych to DATE.
Spróbuj tego:
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, ogólna
Oczywiście jest to metoda, dlatego jest ogólna, może być użyta do określenia From_
i To_
dowolnego zakresu danych (tutaj Date
zakres), na podstawie dowolnej zmiany danych (tutaj zmiana Price
).
Tutaj Twoje Dates
są kolejne, więc określenie Date_Next
jest proste:zwiększ Date
o 1 dzień. Jeśli PK rośnie, ale nie kolejne (np. DateTime
lub TimeStamp
lub inny klucz), zmień tabelę pochodną X
do:
-- 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
Ciesz się.
Zachęcamy do komentowania, zadawania pytań itp.