一行,多个GROUP

时间:2010-06-23 13:57:57

标签: sql mysql

我有一个MySQL数据库中的预留列表,我想确定以15分钟为间隔保留的总时隙数。要做到这一点,我需要“展开”(可能不是正确的单词)每个预订,确定重叠,并显示总使用量。

该表是预订列表:

ResID              StartTime                EndTime         SlotsUsed  
1            2010-06-13 12:00:00      2010-06-13 12:59:00      10  
2            2010-06-13 12:00:00      2010-06-13 12:29:00      5  
3            2010-06-13 12:30:00      2010-06-13 13:29:00      15  

我想要的输出是这样的:

       Time            SlotsInUse  
2010-06-13 12:00:00        15   
2010-06-13 12:15:00        15  
2010-06-13 12:30:00        25  
2010-06-13 12:45:00        25  
2010-06-13 13:00:00        15  

在SQL之外,我可以很容易地使用日期时间数学&列表/数组。但是无论如何要在SELECT语句本身中执行它,以某种方式对项目进行正确的分组,并使用sum()

4 个答案:

答案 0 :(得分:1)

这样做的诀窍是获取一个间隔列表。为此,您需要一个Numbers或Tally表,它是一个包含整数顺序列表的静态表。

Create Temporary Table Test
    (
    ResId int not null
    , StartTime datetime not null
    , EndTime datetime not null
    , SlotsUsed int not null
    )
Insert Test(ResId, StartTime, EndTime, SlotsUsed) Values(1, '2010-06-13 12:00:00','2010-06-13 12:59:00',10)  
Insert Test(ResId, StartTime, EndTime, SlotsUsed) Values(2, '2010-06-13 12:00:00','2010-06-13 12:29:00',5 )
Insert Test(ResId, StartTime, EndTime, SlotsUsed) Values(3, '2010-06-13 12:30:00','2010-06-13 13:29:00',15   )
------
Create Temporary Table Numbers ( Value int not null )
Insert Numbers(Value) Values(1)
Insert Numbers(Value) Values(2)
Insert Numbers(Value) Values(3)
Insert Numbers(Value) Values(4)
Insert Numbers(Value) Values(5)
Insert Numbers(Value) Values(6)
...

Select Intervals.[Date], Sum(SlotsUsed)
From    (
        Select Date_Add( '2010-06-13 12:00:00', INTERVAL + (15 * N.Value) MINUTE ) As [Date], T.SlotsUsed
        From Test As T
            Join Numbers As N
                On Date_Add( '2010-06-13 12:00:00', INTERVAL + (15 * N.Value) MINUTE ) Between T.StartTime And T.EndTime
        ) As Intervals
Group By Intervals.[Date]

在这里,我随意选择2010-06-13 12:00:00作为确定间隔的开始时间。但是,只要您的Numbers表大到足以计算给定日期内的所有间隔(即至少有96个值),您就可以轻松使用DATE(T.StartTime)

答案 1 :(得分:0)

你可以做的是事先查询总范围,这样你就有了结束时间。然后,您可以使用UNION生成一个巨大的SQL,它将为您提供所有这些间隔的结果,如下所示:

SELECT Sum(SlotsUsed), $interval1 FROM table WHERE startime <= $interval1 AND endtime >= $interval1
UNION
SELECT Sum(SlotsUsed), $interval2 FROM table WHERE startime <= $interval2 AND endtime >= $interval2
UNION
...

然而,如果这是可行的话,那就没有任何线索了。

在DB2中,你可以这样做来改善查询的大小,也许在MySQL中有类似的东西:

SELECT Sum(SlotsUsed), I.Interval
FROM table, (VALUES ($interval1), ($interval2), ..., ($intervalN) ) I(Interval)
WHERE table.startime <= I.Interval AND table.endtime >= I.Interval
GROUP BY I.Interval

答案 2 :(得分:0)

这可能对你有用。我没有测试它,当我翻译成实际的sql时,我通常必须修复我的SQL ...

  • 使用日期时间列
  • 创建临时表(时间表)
  • 插入您要报告的15分钟间隔
  • select time,sum(slotsused) from temp left outer join reservations on timetable between(starttime,endtime) group by time

答案 3 :(得分:0)

我建议使用循环。您可以在Database Journal找到有关循环的更多信息。

我不确定如何但是如果你可以将每次循环结果组合在一起将insert语句更改为select。但是因为我不知道如何做到这一点,或者如果有可能,你可以更容易地创建一个临时表,然后只需select *。这是未经测试的伪代码,但您可以执行以下操作:

Create tempTable Values ResID, StartTime, EndTime, SlotsUsed 
Declare @min datetime
Declare @max datetime
Set @min = (SELECT MIN(StartTime) FROM Table)
Set @max = (SELECT MAX(EndTime) FROM Table)

Some how round @min to nearest hour or 15 minute increment
for example : 2010-06-13 12:10:00 to 2010-06-13 12:00:00
              2010-06-13 12:34:00 to 2010-06-13 12:00:00 OR 2010-06-13 12:30:00

DECLARE @case_exit int
SET @counter = 0
while @counter < 1
  begin
  insert into tempTable Time = @min, SlotsInUse = (
        SELECT SUM(SlotsUsed) FROM table WHERE @min => StartTime AND @min =< EndTime)
  @min = @min + 15 minutes
  end

SELECT * from TempTable