2009-10-07 6 views
1

J'ai un peu de «brain fade» en cours cet après-midi, donc si quelqu'un peut aider avec cette requête mssql, ce serait fantastique.Requête SQL Server pour regrouper des données de date séquentielles

J'ai une table appelée « saisons » avec trois colonnes (il y a plus, mais rien à voir l'exemple): seasonId, date, tariffId

SeasonId est une clé unique. Une date ne peut avoir qu'un seul tarif, mais un ID de tarif peut avoir plusieurs dates différentes.

Par exemple:

seasonId | date  | tariffId 
---------------------------------- 
     1 | 1 jan 2009 |   1 
     2 | 2 jan 2009 |   1 
     3 | 3 jan 2009 |   2 
     4 | 4 jan 2009 |   3 
     5 | 5 jan 2009 |   3 

Je voudrais avoir une requête retourner la séquence/plage de dates sur un tariffId particulier

Par exemple, en utilisant les données ci-dessus, il retournerait les éléments suivants:

FromDate | ToDate | TariffId 
----------------------------------- 
     1 | Jan 2009 2 | Jan 2009 1 
     3 | Jan 2009 3 | Jan 2009 2 
     4 | Jan 2009 5 | Jan 2009 3 

Est-ce possible?

EDIT Merci pour toutes les réponses! Je suis toujours étonné de voir jusqu'où vous obtenez une réponse!

Cependant, mon exemple des données était probablement pas assez complexe comme gammes tarifaires peut avoir 1 jour ou plus

seasonId | date  | tariffId 
---------------------------------- 
     1 | 1 jan 2009 |   1 
     2 | 2 jan 2009 |   1 
     3 | 3 jan 2009 |   2 
     4 | 4 jan 2009 |   3 
     5 | 5 jan 2009 |   3 
     6 | 6 jan 2009 |   1 
     7 | 7 jan 2009 |   1 
     8 | 8 jan 2009 |   3 

Donnerait:

FromDate |  ToDate | TariffId 
------------------------------------ 
1 Jan 2009 | 2 Jan 2009 |   1 
3 Jan 2009 | 3 Jan 2009 |   2 
4 Jan 2009 | 5 Jan 2009 |   3 
6 Jan 2009 | 7 Jan 2009 |   1 
8 Jan 2009 | 8 Jan 2009 |   3 

Idées?

Merci à tous pour votre aide à ce sujet! Ce site est génial!

Répondre

3

Tout d'abord quelques données de test:

create table seasons (seasonId int primary key 
    , "date" datetime not null unique 
    , tariffId int not null) 

insert into seasons values (1, '2009-01-01', 1) 
insert into seasons values (2, '2009-01-02', 1) 
insert into seasons values (3, '2009-01-03', 2) 
insert into seasons values (4, '2009-01-04', 3) 
insert into seasons values (5, '2009-01-05', 3) 
insert into seasons values (6, '2009-01-06', 1) 
insert into seasons values (7, '2009-01-07', 1) 
insert into seasons values (8, '2009-01-08', 3) 
-- add a tarrif with a datespan larger than 2 
insert into seasons values (9, '2009-01-09', 4) 
insert into seasons values (10, '2009-01-10', 4) 
insert into seasons values (11, '2009-01-11', 4) 

Miser sur la réponse de Dave Barker, dans les vues inline ajouter row_number() donc nous savons qui sont les premières valeurs min, ce qui est le deuxième, etc. par tariffId. (En fait, depuis une date ne peut pas avoir plus d'un tariffId, on n'a pas besoin de partitionner par tariffId.)

SELECT MinValues.Seasonid, MinValues.Date, MaxValues.Date, MaxValues.tariffid 
FROM (
    SELECT *, row_number() over (partition by tariffId order by "date") as RN 
     FROM [dbo].[Seasons] tbl1 
    WHERE NOT EXISTS (SELECT * 
         FROM [dbo].[Seasons] tbl2 
         WHERE tbl1.seasonid - tbl2.seasonid = 1 
          AND tbl1.tariffId = tbl2.tariffId)) as minValues 
JOIN (
    SELECT *, row_number() over (partition by tariffId order by "date") as RN 
     FROM [dbo].[Seasons] tbl1 
     WHERE NOT EXISTS (SELECT * 
          FROM [dbo].[Seasons] tbl2 
         WHERE tbl2.seasonid - tbl1.seasonid = 1 
          AND tbl1.tariffId = tbl2.tariffId)) as maxValues 
ON MinValues.TariffId = MaxValues.tariffId 
and MinValues.RN = MaxValues.RN 
order by MinValues.Date 

Résultats:

1 2009-01-01 00:00:00.000 2009-01-02 00:00:00.000 1 
3 2009-01-03 00:00:00.000 2009-01-03 00:00:00.000 2 
4 2009-01-04 00:00:00.000 2009-01-05 00:00:00.000 3 
6 2009-01-06 00:00:00.000 2009-01-07 00:00:00.000 1 
8 2009-01-08 00:00:00.000 2009-01-08 00:00:00.000 3 
9 2009-01-09 00:00:00.000 2009-01-11 00:00:00.000 4 
+0

Fantastique - excellente explication et exemples de code. Merci pour votre temps –

0

Peut-être que cela?

select min(fromdate) as FromDate, max(todate) as ToDate, tarifid 
from (

select min(date) as fromdate, null as todate, tarifid 
from seasons 
group by tarifid 

union 

select null, max(date), tarifid 
from seasons 
group by tarifid 

) q 
group by tarifid 
2
SELECT min(date) as FromDate, MAX(date) as ToDate, tarifid 
FROM seasons 
GROUP BY tarifID 

devrait le faire.

+0

Je ne me souviens pas quand, mais je me souviens que pas toujours ... – eKek0

+0

Si vous pouvez trouver un scénario où cela ne fonctionne pas, j'aimerais bien le savoir car je l'utilise assez souvent.Si quelque chose me manque, j'aimerais en savoir plus. –

+0

Dans les résultats plus détaillés, le tarifid de 1 apparaît plus d'une fois dans les résultats. Cet exemple ne retournera qu'une ligne. –

0

Il semble que vous trouviez les occurrences séquentielles de tariffId, puis que vous trouviez les valeurs minimum et maximum de Date dans cette occurrence séquentielle. Les travaux suivants pour vos données d'échantillon, mais je soupçonne que la jointure finale a besoin de quelques ajustements, car il sent malodorant.

SELECT MinValues.Seasonid, MinValues.Date, MaxValues.Date, MaxValues.tariffid 
FROM (
    SELECT * 
     FROM [dbo].[Seasons] tbl1 
    WHERE NOT EXISTS (SELECT * 
         FROM [dbo].[Seasons] tbl2 
         WHERE tbl1.seasonid - tbl2.seasonid = 1 
          AND tbl1.tariffId = tbl2.tariffId)) as minValues 
JOIN (
    SELECT * 
     FROM [dbo].[Seasons] tbl1 
     WHERE NOT EXISTS (SELECT * 
          FROM [dbo].[Seasons] tbl2 
         WHERE tbl2.seasonid - tbl1.seasonid = 1 
          AND tbl1.tariffId = tbl2.tariffId)) as maxValues 
ON MinValues.TariffId = MaxValues.tariffId 
AND (MinValues.SeasonId = MaxValues.Seasonid or MinValues.SeasonId +1 = MaxValues.Seasonid) 
+0

La jointure finale ne fonctionnera pas si la plage de dates est supérieure à deux jours. –

2
SELECT min(date) as FromDate,MAX(date) as ToDate, tariffid FROM(
select s.*,ISNULL(
(SELECT MAX(seasonID) FROM seasons s1 WHERE s.tariffid <> s1.tariffid AND s1.seasonID < s.seasonID),0) as ranks from seasons s)r 
GROUP BY tariffID,ranks 
Questions connexes