sql查询组由连续日期中某个范围的数据组成

时间:2015-06-27 06:00:32

标签: sql sql-server

我想在连续日期内按一定范围内的数据编写一个sql来查询组。我可以使用T-SQL。

表:

Date     |  MeterNo|   Data  |
---------|---------|---------|
01-06-15 |  12345  |      10 |
02-06-15 |  12345  |      12 |
03-06-15 |  12345  |      51 |
04-06-15 |  12345  |      56 |
05-06-15 |  12345  |      16 |  
06-06-15 |  12345  |      15 |
07-06-15 |  12345  |      9  |
08-06-15 |  12345  |      53 |
09-06-15 |  12345  |      55 |
10-06-15 |  12345  |      62 |
11-06-15 |  12345  |      8  |
12-06-15 |  12345  |      18 |

我想通过以下结果进行分组:

|MeterNo| GroupName| StartDate |  EndDate |
|-------|----------|-----------|--------- |
| 12345 |  0(<50)  |  01-06-15 |  02-06-15| 
| 12345 |  1(>=50) |  03-06-15 |  04-06-15| 
| 12345 |  0(<50)  |  05-06-15 |  07-06-15| 
| 12345 |  1(>=50) |  08-06-15 |  10-06-15| 
| 12345 |  0(<50)  |  11-06-15 |  12-06-15| 

我需要将数据分组在连续日期中小于50且大于50,如下所示。 如何获取SQL查询以获得第二个结果表的结果?提前谢谢!

2 个答案:

答案 0 :(得分:3)

这基本上是间隙和岛屿问题,您可以使用行号将日期范围分组,并根据固定日期的每个日期的距离进行检查,例如日期0(= 1.1.1900)。所以你可以得到结果:

select
  MeterNo,
  Grp,
  min(Date) as StartDate,
  max(Date) as EndDate
from (
  select
    MeterNo,
    Date,
    Grp,
    datediff(day, 0, Date) - RN as DateGroup
  from (
    select
      Date,
      MeterNo,
      case when Data >= 50 then 1 else 0 end as Grp,
      row_number() over (partition by MeterNo, 
          case when Data >= 50 then 1 else 0 end order by date asc) as RN
    from
      table1
    ) X
  ) Y
group by
  MeterNo,
  Grp,
  DateGroup
Order by
  MeterNo,
  StartDate

您可以在SQL Fiddle

中对此进行测试

答案 1 :(得分:1)

一些替代解决方案:

declare @t table([Date] date, [MeterNo] int, [Data] int);

INSERT INTO @t VALUES
    ('2015-06-01', 12345, 10),
    ('2015-06-02', 12345, 12),
    ('2015-06-03', 12345, 51),
    ('2015-06-04', 12345, 56),
    ('2015-06-05', 12345, 16),
    ('2015-06-06', 12345, 15),
    ('2015-06-07', 12345, 9),
    ('2015-06-08', 12345, 53),
    ('2015-06-09', 12345, 55),
    ('2015-06-10', 12345, 62),
    ('2015-06-11', 12345, 8),
    ('2015-06-12', 12345, 18);

with cte as(select *,
                   case when data < 50 then 0 else 1 end gr1,
                   ROW_NUMBER() over(partition by MeterNo order by date)-
                   ROW_NUMBER() over(partition by MeterNo, 
                                                  case when data < 50 then 0 else 1 end 
                                     order by date) gr2
           from @t)
select MeterNo, 
       MIN(date) StartDate, 
       MAX(date) EndDate,
       case when gr1 = 0 then '0(<50)' else '1(>=50)' end as GroupName
from cte
group by MeterNo, gr1, gr2
order by StartDate