Ikke-relationel løsning
Jeg tror ikke, at nogen af de andre svar er rigtige.
-
GROUP BY
virker ikke -
Bruger
ROW_NUMBER()
tvinger dataene ind i en Record Filing System-struktur, som er fysisk, og behandler dem derefter som fysiske poster. Til enorme præstationsomkostninger. For at kunne skrive en sådan kode tvinger det dig selvfølgelig til at tænke i form af RFS i stedet for at tænke i relationelle termer. -
Brug af CTE'er er det samme. Iteration gennem data, især data, der ikke ændrer sig. Til en lidt anderledes massiv pris.
-
Markører er bestemt den forkerte ting af forskellige årsager. (a) Markører kræver kode, og du har anmodet om en visning (b) Markører forlader sæt-behandlingsmotoren og vender tilbage til række-for-række-behandling. Igen, ikke påkrævet. Hvis en udvikler på et af mine teams bruger markører eller midlertidige tabeller på en relationsdatabase (dvs. ikke et registreringssystem), skyder jeg dem.
Relationel løsning
-
Dine data er Relationel, logisk, de to givne data kolonner er alt, hvad der er nødvendigt.
-
Selvfølgelig skal vi danne en visning (afledt relation) for at opnå den ønskede rapport, men den består af rene SELECT'er, som er helt anderledes end behandling (konvertering til en fil , som er fysisk, og derefter behandle filen; eller vikarborde; eller arbejdsborde; eller CTE'er; eller ROW_Number(); osv.).
-
I modsætning til beklagelserne fra "teoretikere", som har en dagsorden, håndterer SQL Relationelle data udmærket. Og dine data er relationelle.
Oprethold derfor en Relationel tankegang, en Relationel opfattelse af dataene og en set-bearbejdningsmentalitet. Ethvert rapportkrav over en relationsdatabase kan opfyldes ved hjælp af et enkelt SELECT. Der er ingen grund til at gå tilbage til ISAM-filhåndteringsmetoder før 1970.
Jeg vil antage, at den primære nøgle (det sæt af kolonner, der giver en relationel række unikke) er Date,
og baseret på de angivne eksempeldata er datatypen DATE.
Prøv dette:
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
Metode, generisk
Selvfølgelig er dette en metode, derfor er den generisk, den kan bruges til at bestemme From_
og To_
af ethvert datainterval (her en Date
interval), baseret på enhver dataændring (her en ændring i Price
). ).
Her er dine Dates
er fortløbende, så bestemmelsen af Date_Next
er enkel:forøg Date
inden for 1 dag. Hvis PK er stigende, men ikke fortløbende (f.eks. DateTime
eller TimeStamp
eller en anden nøgle), ændre den afledte tabel X
til:
-- 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
God fornøjelse.
Du er velkommen til at kommentere, stille spørgsmål osv.