sql >> Base de Datos >  >> Database Tools >> SSMS

Intervalo de fechas para el conjunto de los mismos datos

Solución no relacional

No creo que ninguna de las otras respuestas sea correcta.

  • GROUP BY no funcionará

  • Usando ROW_NUMBER() fuerza los datos en una estructura de sistema de archivo de registros, que es física, y luego los procesa como registros físicos. A un costo de rendimiento masivo. Por supuesto, para escribir dicho código, te obliga a pensar en términos de RFS en lugar de pensar en términos relacionales.

  • Usar CTE es lo mismo. Iterando a través de los datos, especialmente los datos que no cambian. A un costo masivo ligeramente diferente.

  • Los cursores definitivamente son algo incorrecto por un conjunto diferente de razones. (a) Los cursores requieren código y usted ha solicitado una Vista (b) Los cursores abandonan el motor de procesamiento de conjuntos y vuelven al procesamiento fila por fila. Nuevamente, no es obligatorio. Si un desarrollador de alguno de mis equipos usa cursores o tablas temporales en una base de datos relacional (es decir, no en un sistema de archivo de registros), le disparo.

Solución Relacional

  1. Tus datos es relacional, lógico, los dos dados datos las columnas son todo lo que se necesita.

  2. Claro, tenemos que formar una Vista (Relación derivada) para obtener el informe deseado, pero eso consiste en SELECCIONES puras, que es bastante diferente al procesamiento (convertirlo en un archivo , que es físico, y luego procesa el archivo; o tablas temporales; o mesas de trabajo; o CTE; o FILA_Número(); etc.).

  3. Contrariamente a las lamentaciones de los "teóricos", que tienen una agenda, SQL maneja perfectamente los datos relacionales. Y sus datos son relacionales.

Por lo tanto, mantenga una mentalidad relacional, una visión relacional de los datos y una mentalidad de procesamiento de conjuntos. Cada requisito de informe sobre una base de datos relacional se puede cumplir con un solo SELECT. No hay necesidad de regresar a los métodos de manejo de archivos ISAM anteriores a 1970.

Asumiré que la clave principal (el conjunto de columnas que dan un carácter único a una fila relacional) es Date, y según los datos de ejemplo proporcionados, el tipo de datos es DATE.

Prueba esto:

    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

Método, Genérico

Por supuesto, este es un método, por lo tanto, es genérico, se puede usar para determinar el From_ y To_ de cualquier rango de datos (aquí, una Date rango), basado en cualquier cambio de datos (aquí, un cambio en Price ).

Aquí, sus Dates son consecutivos, por lo que la determinación de Date_Next es simple:incrementa la Date por 1 día. Si el PK está aumentando pero no consecutivos (por ejemplo, DateTime o TimeStamp o alguna otra Clave), cambie la Tabla Derivada 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

Disfruta.

No dude en comentar, hacer preguntas, etc.