2010-02-18 51 views
7

我不得不下表中的SQL Server:SQL查询来解决以下

date     | status 

2009-01-01 12:00:00  OK 
2009-01-01 12:03:00  FAILED 
2009-01-01 12:04:00  OK 
2009-01-01 12:06:20  OK 
2009-01-01 12:07:35  FAILED 
2009-01-01 12:07:40  FAILED 
2009-01-01 12:20:40  FAILED 
2009-01-01 12:25:40  OK 

我需要以下条件:起始2009-01-01 12:00:00,从该日起,我需要每10分钟查看OK和FAILED的数量。

类似:

INTERVAL         FAILED  OK 
2009-01-01 12:00:00-2009-01-01 12:15:00 1   2 
2009-01-01 12:15:01-2009-01-01 12:30:00 0   1 

等。

什么是SQL做到这一点的最好方法是什么?

+1

你说每隔10分钟,但例子显示每15 .. – 2010-02-18 22:39:00

回答

2

好吧首先是..

你提到的10分钟,提供15分钟的例子..另外,你的样品数据是否比你贴什么返回不同的结果..

解决方案使用透视

Declare @datetimestart datetime 
Declare @interval int 
Set @datetimestart = '2009-01-01 12:00:00' 
Set @interval = 15 

Select 
    * 
From 
    (
    Select 
    DateAdd(Minute,Floor(DateDiff(Minute,@datetimestart,[date])/@interval)*@interval 
,@datetimestart), 
    DateAdd(Minute,@interval + Floor(DateDiff(Minute,@datetimestart,[date])/@interval)*@interval 
,@datetimestart) 
, status 
    From dtest 
) As W([from],[to], status) 
Pivot (Count(status) For status In ([ok],[failed])) p 

这将返回

From      To      Ok Failed 
2009-01-01 12:00:00.000 2009-01-01 12:15:00.000  3 3 
2009-01-01 12:15:00.000 2009-01-01 12:30:00.000  1 0 

评论

这个版本将包括没有在数据库中值的时间间隔.. 我们需要动态创建一个临时表后更新..

Declare @datetimestart datetime, @datetimeend datetime, @datetimecurrent datetime 
Declare @interval int 
Set @datetimestart = '2009-01-01 12:00:00' 
Set @interval = 10 
Set @datetimeend = (Select max([date]) from dtest) 

SET @datetimecurrent = @datetimestart 

declare @temp as table ([from] datetime,[to] datetime) 
while @datetimecurrent < @datetimeend 
BEGIN 
    insert into @temp select (@datetimecurrent), dateAdd(minute, @interval, @datetimecurrent) 
    set @datetimecurrent = dateAdd(minute, @interval, @datetimecurrent) 
END 

Select 
    * 
From 
    (
    Select 
     [from],[to], status 
    From @temp t left join dtest d on d.[date] between t.[from] and t.[to] 
) As W([from],[to], status) 
Pivot (Count(status) For status In ([ok],[failed])) p 

现在使用10分钟的时间间隔,显示无数值的时间段,返回..

From      To      Ok Failed 
2009-01-01 12:00:00.000 2009-01-01 12:10:00.000  3 3 
2009-01-01 12:10:00.000 2009-01-01 12:20:00.000  0 0 
2009-01-01 12:20:00.000 2009-01-01 12:30:00.000  1 0 
+0

有一次,我想让我的头绕着枢轴做什么,我意识到这是由awsome构成的,*和*它只用一个表扫描! – 2010-02-19 14:41:32

+0

(*点头*)(*点头*)..很酷的东西。只有了解了它最近我自己..从SO;) – 2010-02-19 14:55:59

+0

的解决方案是好的,但被跳过的时间间隔.. dt_from \t dt_to \t CONNECTING \t失败\t TEMINATED \t CONNECTED 2010-02-05 19:15:00.000 \t 2010-02-05 19:30:00.000 \t 2010-02-05 19:45:00.000 \t 2010-02-05 20:00:00.000 2010-02-05 20:00:00.000 \t 2010-02-05 20:15:00 0.000 \t 2010-02-05 20:30:00.000 \t 2010-02-05 20:45:00.000 \t \t – stefan 2010-02-19 21:08:04

0

因为我不知道你的表名,所以像这样的东西应该工作。

DECLARE @startTime DATETIME 
DECLARE @endTime DATETIME 

SELECT @startTime = '1/1/2010 00:00:00' 
SELECT @endTime = GETDATE() 

SELECT 
    cast(@startTime as varchar) + ' - ' + cast(@endTime as varchar) as Interval, 
    (select count(1) from [table] where status = 'FAILED') as FAILED, 
(Select count(1) from [table where status = 'OK') as OK 
FROM 
    [table] 
WHERE 
    date between @startTime and @endTime 
+0

这不考虑你需要的时间间隔,但你可以用它来手动选择时间范围。 – 2010-02-18 22:49:24

+0

你必须做一个循环来获得所有的结果。 – 2010-02-18 22:53:21

1

有可能是做一个更简单的方法,但这个工程:

--CREATE TABLE temptest 
--(
-- date1 DATETIME, 
-- stat nvarchar(10) 
--) 

--INSERT INTO temptest 
--VALUES 
--('2009-01-01 12:00:00','OK'), 
--('2009-01-01 12:03:00','FAILED'), 
--('2009-01-01 12:04:00','OK'), 
--('2009-01-01 12:06:20','OK'), 
--('2009-01-01 12:07:35','FAILED'), 
--('2009-01-01 12:07:40','FAILED'), 
--('2009-01-01 12:20:40','FAILED'), 
--('2009-01-01 12:25:40','OK') 

SELECT 
    stat, 
    COUNT(1), 
    YEAR(date1), 
    MONTH(date1), 
    DAY(date1), 
    DATEPART(hh,date1), 
    ROUND(DATEPART(MINUTE,date1)/10,0) 
FROM temptest 
GROUP BY stat, YEAR(date1), MONTH(date1), DAY(date1), DATEPART(hh,date1), ROUND(DATEPART(MINUTE,date1)/10,0) 
0

这是使用递归CTE。

declare @startdate datetime 
declare @enddate datetime 
declare @interval int 

set @startdate = '2009-01-01 12:00:00' 
set @enddate = '2009-01-02 12:00:00' 
set @interval = 15 

;with intervals (i, d) AS 
(
    select 1, @startdate 
    union all 
    select i+1, DATEADD(MINUTE, (@interval*i), @startdate) from intervals where i < 100 
) 
select d as 'From', DATEADD(MINUTE, (@interval-1), d) as 'To', 
    (select COUNT(*) from yourTable where thedate between d and DATEADD(MINUTE, (@interval-1), d) and thestatus = 'FAILED') as 'FAILED', 
    (select COUNT(*) from yourTable where thedate between d and DATEADD(MINUTE, (@interval-1), d) and thestatus = 'OK') as 'OK' 
from intervals 
option (MAXRECURSION 100) 

输出看起来是这样的:

From     To      FAILED  OK 
----------------------- ----------------------- ----------- ----------- 
2009-01-01 12:00:00.000 2009-01-01 12:14:00.000 3   3 
2009-01-01 12:15:00.000 2009-01-01 12:29:00.000 1   1 
2009-01-01 12:30:00.000 2009-01-01 12:44:00.000 0   0 
2009-01-01 12:45:00.000 2009-01-01 12:59:00.000 0   0 
2009-01-01 13:00:00.000 2009-01-01 13:14:00.000 0   0 
2009-01-01 13:15:00.000 2009-01-01 13:29:00.000 0   0 
2009-01-01 13:30:00.000 2009-01-01 13:44:00.000 0   0 

请注意,你的数据,你有相同数量的失败,确定在时隙。

0

Anothe r选项...

CREATE TABLE #results (IntervalStart DATETIME, IntervalEnd DATETIME, FailedCount INT, OKCount INT); 
DECLARE @EndPoint DATETIME 
DECLARE @CurrentPoint DATETIME 
DECLARE @PeriodEnd DATETIME 

SET @CurrentPoint = '2009-01-01 12:00:00' 
SET @EndPoint = '2009-03-01 12:00:00' -- choose any end point, could be today: GETDATE() 

WHILE @CurrentPoint < @EndPoint 
BEGIN 
    SET @PeriodEnd = DATEADD(mi, 10, @CurrentPoint) 

    INSERT INTO #results 
    SELECT @CurrentPoint, @PeriodEnd, 
     (SELECT COUNT(Status) FROM StatusSource WHERE StatusPoint BETWEEN @CurrentPoint AND @PeriodEnd AND Status = 'FAILED'), 
     (SELECT COUNT(Status) FROM StatusSource WHERE StatusPoint BETWEEN @CurrentPoint AND @PeriodEnd AND Status = 'OK') 

    SET @CurrentPoint = @PeriodEnd 
END 

SELECT 
    CAST(@IntervalStart AS VARCHAR(20)) + ' - ' + cast(@IntervalEnd AS VARCHAR(20)) as Interval, 
    FailedCount AS FAILED, 
    OKCount AS OK 
FROM 
    #results 

DROP TABLE #results 
0

这里是理货表版本。

设置一些虚拟的数据:

/* 

CREATE TABLE MyTable 
( 
    MyDate DATETIME, 
    Status varchar(10) 
) 

INSERT INTO Mytable VALUES ('2009-01-01 12:00:00','OK') 
INSERT INTO Mytable VALUES ('2009-01-01 12:03:00','FAILED') 
INSERT INTO Mytable VALUES ('2009-01-01 12:04:00','OK') 
INSERT INTO Mytable VALUES ('2009-01-01 12:06:20','OK') 
INSERT INTO Mytable VALUES ('2009-01-01 12:07:35','FAILED') 
INSERT INTO Mytable VALUES ('2009-01-01 12:07:40','FAILED') 
INSERT INTO Mytable VALUES ('2009-01-01 12:20:40','FAILED') 
INSERT INTO Mytable VALUES ('2009-01-01 12:25:40','OK') 

*/ 

设置值和paramters。我将所有内容硬编码了10分钟,但这也可能是一个参数。

DECLARE 
    @StartAt datetime 
,@Through datetime 

SET @StartAt = 'Jan 1, 2009' 
SET @Through = getdate() -- or whenever 

然后查询。这仅在存在要列出的数据时才列出行;使其成为内部连接以列出没有活动的“时隙”。

;WITH 
    -- Itzik Ben-Gan's tally table routine 
    Pass0 as (select 1 as C union all select 1), --2 rows 
    Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows 
    Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows 
    Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows 
    Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows 
    Pass5 as (select 1 as C from Pass4 as A, Pass4 as B),--4,294,967,296 rows 
    Tally as (select row_number() over(order by C) as Number from Pass5) 

(...在“理货表”或“号码表”中查找讨论什么,和为什么这背后...的)

select 
    xx.FromTime 
    ,sum(case when mt.Status = 'OK' then 1 else 0 end)  HowManyOk 
    ,sum(case when mt.Status = 'Failed' then 1 else 0 end) HowManyFailed 
    from (select 
      dateadd(mi, (Number-1) * 10, @StartAt) FromTime 
      ,dateadd(mi, Number * 10, @StartAt)  ThruTime 
     from Tally where Number <= datediff(mi, @StartAt, @Through) /10) xx 
    inner join MyTable mt 
    on mt.MyDate >= xx.FromTime and mt.MyDate < xx.ThruTime 
    group by xx.FromTime 

所以我的问题是:所有提出的方法,随着数据量的增加,规模越大?我希望有人测试这个。

+0

从一些非常基本的基准测试里面的SQL Serrver管理工作室(*代码在一个循环中,并采取前后时间*),我建议的版本执行显着fa除了理货之外 – 2010-02-19 11:07:56