SSMS
 sql >> Datenbank >  >> Database Tools >> SSMS

Datumsbereich für denselben Datensatz

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

  1. Ihre Daten ist relational, logisch, die beiden gegebenen Daten Spalten sind alles, was notwendig ist.

  2. 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.).

  3. 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.