Icke-relationell lösning
Jag tror inte att något av andra svar är korrekta.
-
GROUP BY
fungerar inte -
Använder
ROW_NUMBER()
tvingar in uppgifterna i en arkiveringssystemstruktur, som är fysisk, och bearbetar den sedan som fysiska arkiv. Till en enorm prestationskostnad. Naturligtvis, för att skriva sådan kod, tvingar den dig att tänka i termer av RFS istället för att tänka i relationella termer. -
Att använda CTE är samma sak. Itererar genom data, särskilt data som inte förändras. Till en lite annorlunda massiv kostnad.
-
Markörer är definitivt fel av olika anledningar. (a) Markörer kräver kod, och du har begärt en vy (b) Markörer överger uppsättningsbearbetningsmotorn och återgår till rad-för-rad-behandling. Återigen, inte nödvändigt. Om en utvecklare i något av mina team använder markörer eller tillfälliga tabeller i en relationsdatabas (dvs. inte ett registerarkiveringssystem), skjuter jag dem.
Relationell lösning
-
Dina data är Relationell, logisk, de två givna data kolumner är allt som behövs.
-
Visst, vi måste bilda en vy (härledd relation) för att få den önskade rapporten, men den består av rena SELECT, vilket skiljer sig ganska mycket från bearbetning (konvertera den till en fil , som är fysisk, och bearbetar sedan filen; eller temp tabeller; eller arbetsbord; eller CTE; eller ROW_Number(); etc).
-
I motsats till klagomålen från "teoretiker", som har en agenda, hanterar SQL Relationell data utmärkt. Och din data är relationell.
Upprätthåll därför ett relationellt tänkesätt, en relationell syn på data och en uppsättningsbearbetningsmentalitet. Varje rapportkrav över en relationsdatabas kan uppfyllas med ett enda SELECT. Det finns inget behov av att gå tillbaka till ISAM-filhanteringsmetoder före 1970.
Jag antar att den primära nyckeln (uppsättningen kolumner som ger en relationell rad unikhet) är Date,
och baserat på exempeldata som ges är datatypen DATE.
Prova detta:
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
Metod, Generisk
Naturligtvis är detta en metod, därför är den generisk, den kan användas för att bestämma From_
och To_
för alla dataintervall (här ett Date
intervall), baserat på eventuell dataändring (här, en ändring i Price
).
Här, dina Date
är på varandra följande, så bestämningen av Date_Next
är enkelt:öka Date
med 1 dag. Om PK ökar men inte på varandra följande (t.ex. DateTime
eller TimeStamp
eller någon annan nyckel), ändra den härledda tabellen X
till:
-- 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
Njut.
Kommentera gärna, ställ frågor etc.