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

Intervallo di date per l'insieme degli stessi dati

Soluzione non relazionale

Non credo che nessuna delle altre risposte sia corretta.

  • GROUP BY non funzionerà

  • Utilizzando ROW_NUMBER() forza i dati in una struttura del sistema di archiviazione dei record, che è fisica, e quindi li elabora come record fisici. Ad un costo di prestazioni enorme. Ovviamente, per scrivere un codice del genere, ti obbliga a pensare in termini di RFS invece di pensare in termini relazionali.

  • L'uso dei CTE è lo stesso. Iterazione attraverso i dati, in particolare i dati che non cambiano. A un costo enorme leggermente diverso.

  • I cursori sono sicuramente la cosa sbagliata per una serie di motivi diversi. (a) I cursori richiedono il codice e tu hai richiesto una vista (b) I cursori abbandonano il motore di elaborazione delle impostazioni e tornano all'elaborazione riga per riga. Ancora una volta, non richiesto. Se uno sviluppatore di uno dei miei team utilizza cursori o tabelle temporanee su un database relazionale (cioè non un sistema di archiviazione dei record), gli sparo.

Soluzione relazionale

  1. I tuoi dati è Relazionale, logico, i due dati dati le colonne sono tutto ciò che è necessario.

  2. Certo, dobbiamo formare una vista (relazione derivata), per ottenere il rapporto desiderato, ma che consiste in SELECT puri, che è abbastanza diverso dall'elaborazione (convertendolo in un file , che è fisico, e quindi elabora il file; o tavoli temporanei; o tavoli da lavoro; o CTE; o RIGA_Numero(); ecc).

  3. Contrariamente alle lamentele dei "teorici", che hanno un'agenda, SQL gestisce perfettamente i dati relazionali. E i tuoi dati sono relazionali.

Pertanto, mantieni una mentalità relazionale, una visione relazionale dei dati e una mentalità di elaborazione degli insiemi. Ogni requisito di report su un database relazionale può essere soddisfatto utilizzando un unico SELECT. Non è necessario regredire ai metodi di gestione dei file ISAM precedenti al 1970.

Presumo che la chiave primaria (l'insieme di colonne che danno un'unicità di riga relazionale) sia Date, e in base ai dati di esempio forniti, il tipo di dati è DATE.

Prova questo:

    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

Metodo, generico

Ovviamente questo è un metodo, quindi è generico, può essere usato per determinare il From_ e To_ di qualsiasi intervallo di dati (qui, una Dates range), in base a qualsiasi modifica dei dati (qui, una modifica in Price ).

Qui, le tue Dates sono consecutive, quindi la determinazione di Date_Next è semplice:incrementa la Date entro 1 giorno. Se il PK è in aumento ma non consecutivi (es. DateTime o TimeStamp o qualche altra chiave), cambia la tabella derivata X a:

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

Divertiti.

Sentiti libero di commentare, porre domande, ecc.