SSMS
 sql >> Base de données >  >> Database Tools >> SSMS

Plage de dates pour un ensemble de données identiques

Solution non relationnelle

Je ne pense pas qu'aucune des autres réponses ne soit correcte.

  • GROUP BY ne fonctionnera pas

  • Utilisation de ROW_NUMBER() force les données dans une structure de système de classement des enregistrements, qui est physique, puis les traite comme des enregistrements physiques. À un coût de performance énorme. Bien sûr, pour écrire un tel code, cela vous oblige à réfléchir en termes de RFS au lieu de penser en termes relationnels.

  • L'utilisation des CTE est la même. Itérer à travers les données, en particulier les données qui ne changent pas. À un coût massif légèrement différent.

  • Les curseurs sont certainement la mauvaise chose pour un ensemble de raisons différentes. (a) Les curseurs nécessitent du code et vous avez demandé une vue (b) Les curseurs abandonnent le moteur de traitement d'ensemble et reviennent au traitement ligne par ligne. Encore une fois, pas obligatoire. Si un développeur de l'une de mes équipes utilise des curseurs ou des tables temporaires sur une base de données relationnelle (c'est-à-dire pas un système de classement d'enregistrements), je les tire.

Solution relationnelle

  1. Vos données est Relationnel, logique, les deux données données les colonnes suffisent.

  2. Bien sûr, nous devons former une vue (relation dérivée), pour obtenir le rapport souhaité, mais cela consiste en des SELECT purs, ce qui est assez différent du traitement (le convertir en un fichier , qui est physique, puis traitement du fichier; ou tables temporaires ; ou tables de travail ; ou CTE ; ou ROW_Number(); etc.).

  3. Contrairement aux lamentations des "théoriciens", qui ont un agenda, SQL gère parfaitement les données relationnelles. Et vos données sont relationnelles.

Par conséquent, maintenez un état d'esprit relationnel, une vision relationnelle des données et une mentalité de traitement d'ensemble. Chaque exigence de rapport sur une base de données relationnelle peut être satisfaite à l'aide d'un seul SELECT. Il n'est pas nécessaire de revenir aux méthodes de gestion des fichiers ISAM antérieures à 1970.

Je supposerai que la clé primaire (l'ensemble de colonnes qui donnent l'unicité d'une ligne relationnelle) est Date, et sur la base des exemples de données donnés, le type de données est DATE.

Essayez ceci :

    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éthode, Générique

Bien sûr c'est une méthode, donc elle est générique, elle peut être utilisée pour déterminer le From_ et To_ de n'importe quelle plage de données (ici, une Date gamme), en fonction de tout changement de données (ici, un changement de Price ).

Ici, vos Dates sont consécutifs, donc la détermination de Date_Next est simple :incrémentez la Date d'ici 1 jour. Si le PK augmente mais pas consécutifs (ex. DateTime ou TimeStamp ou une autre clé), modifiez la table dérivée X à :

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

Profitez-en.

N'hésitez pas à commenter, poser des questions, etc.