2010-02-18 33 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