SQL Server查询以对顺序日期数据进行分组

SQL Server查询以对顺序日期数据进行分组,sql,sql-server,sql-server-2005,tsql,Sql,Sql Server,Sql Server 2005,Tsql,今天下午我有点“大脑衰退”,所以如果有人能帮我处理这个mssql查询,那就太棒了 我有一个名为“seasons”的表,有三列,还有更多但与示例无关的列:seasonId、date、tariffId 季节ID是唯一的键。 一个日期只能有一个tariffid,但tariffid可以有许多不同的日期 例如: seasonId | date | tariffId ---------------------------------- 1 | 1 jan 2009 |

今天下午我有点“大脑衰退”,所以如果有人能帮我处理这个mssql查询,那就太棒了

我有一个名为“seasons”的表,有三列,还有更多但与示例无关的列:seasonId、date、tariffId

季节ID是唯一的键。 一个日期只能有一个tariffid,但tariffid可以有许多不同的日期

例如:

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
我希望有一个查询返回特定tariffId的日期序列/范围

例如,使用上述数据,它将返回以下内容:

FromDate  |  ToDate    |  TariffId
-----------------------------------
       1  | Jan 2009 2 | Jan 2009 1
       3  | Jan 2009 3 | Jan 2009 2
       4  | Jan 2009 5 | Jan 2009 3
这可能吗

编辑 谢谢你迄今为止的所有答案!我总是很惊讶你能得到如此多的回应

然而,我的示例数据可能不够复杂,因为关税可以有1个或多个日期范围

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
将提供:

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

谢谢大家在这方面的帮助!这个网站太棒了

也许是这个

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
也许是这个

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
我应该这样做


应该这样做。

看起来您可以找到tariffId的连续出现,然后在该连续出现中找到日期的最小值和最大值。以下内容适用于您的示例数据,但我怀疑最终连接需要一些调整,因为它感觉很臭

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)

看起来您可以找到tariffId的连续出现,然后在该连续出现中找到日期的最小值和最大值。以下内容适用于您的示例数据,但我怀疑最终连接需要一些调整,因为它感觉很臭

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)
首先是一些测试数据:

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)
基于Dave Barker的回答,在内联视图中添加行数,这样我们就可以通过tariffId知道哪个是第一个最小值,哪个是第二个,等等。实际上,由于一个日期不能有多个tariffId,所以我们不需要按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
结果:

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
首先是一些测试数据:

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)
基于Dave Barker的回答,在内联视图中添加行数,这样我们就可以通过tariffId知道哪个是第一个最小值,哪个是第二个,等等。实际上,由于一个日期不能有多个tariffId,所以我们不需要按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
结果:

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

如果你能想出一个这样不起作用的场景,我很想知道,因为我经常使用它。如果我遗漏了什么,我想了解一下。在更详细的结果中,tarifid of 1在结果中出现了不止一次。这个例子只会返回1行,很明显,这与原来的问题不同:如果你能想出一个这样不起作用的场景,我很想知道,因为我经常使用这个。如果我遗漏了什么,我想了解一下。在更详细的结果中,tarifid of 1在结果中出现了不止一次。这个示例只返回1行。显然,这与原来的问题不同:p如果日期范围大于两天,则最终联接将不起作用。如果日期范围大于两天,则最终联接将不起作用。非常好的解释和代码示例。感谢您的Timeantastic-非常好的解释和代码示例。谢谢你的时间