Nicht relationale Lösung
Ich glaube nicht, dass andere Antworten richtig sind.
-
GROUP BY
wird nicht funktionieren -
Mit
ROW_NUMBER()
zwingt die Daten in eine Record File System-Struktur, die physisch ist, und verarbeitet sie dann als physische Aufzeichnungen. Zu massiven Leistungskosten. Um solchen Code zu schreiben, müssen Sie natürlich nachdenken in Bezug auf RFS, anstatt in relationalen Begriffen zu denken. -
Die Verwendung von CTEs ist die gleiche. Iteration durch die Daten, insbesondere Daten, die sich nicht ändern. Zu etwas anderen massiven Kosten.
-
Cursor sind aus verschiedenen Gründen definitiv das Falsche. (a) Cursor erfordern Code, und Sie haben eine Ansicht angefordert. (b) Cursor verlassen die Set-Processing-Engine und kehren zur zeilenweisen Verarbeitung zurück. Wieder nicht erforderlich. Wenn ein Entwickler in einem meiner Teams Cursor oder temporäre Tabellen in einer relationalen Datenbank (dh nicht in einem Datensatzablagesystem) verwendet, erschieße ich sie.
Relationale Lösung
-
Ihre Daten ist relational, logisch, die beiden gegebenen Daten Spalten sind alles, was notwendig ist.
-
Sicher, wir müssen eine View (abgeleitete Beziehung) bilden, um den gewünschten Bericht zu erhalten, aber das besteht aus reinen SELECTs, was ganz anders ist als die Verarbeitung (Konvertieren in eine Datei). , die physisch ist, und dann die Datei verarbeitet; oder temporäre Tabellen; oder Arbeitstische; oder CTEs; oder ROW_Number(); usw.).
-
Im Gegensatz zu den Klagen von "Theoretikern", die eine Agenda haben, verarbeitet SQL relationale Daten perfekt. Und Ihre Daten sind relational.
Behalten Sie daher eine relationale Denkweise, eine relationale Sicht auf die Daten und eine Set-Processing-Mentalität bei. Jede Berichtsanforderung über eine relationale Datenbank kann mit einem einzigen SELECT erfüllt werden. Es besteht keine Notwendigkeit, auf die Verarbeitungsmethoden von ISAM-Dateien vor 1970 zurückzugreifen.
Ich gehe davon aus, dass der Primärschlüssel (der Satz von Spalten, die einer relationalen Zeile Eindeutigkeit verleihen) Date,
ist und basierend auf den angegebenen Beispieldaten ist der Datentyp DATE.
Versuchen Sie Folgendes:
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
Methode, generisch
Dies ist natürlich eine Methode, daher ist sie generisch, sie kann verwendet werden, um den From_
zu ermitteln und To_
eines beliebigen Datenbereichs (hier ein Date
Bereich), basierend auf einer Datenänderung (hier eine Änderung des Price
).
Hier, Ihre Dates
aufeinander folgen, also die Bestimmung von Date_Next
ist einfach:Erhöhen Sie das Date
um 1 Tag. Wenn der PK steigt, aber nicht fortlaufend (z. B. DateTime
oder TimeStamp
oder ein anderer Schlüssel), ändern Sie die abgeleitete Tabelle X
zu:
-- 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
Viel Spaß.
Bitte fühlen Sie sich frei, zu kommentieren, Fragen zu stellen usw.