sql查询解决以下问题

时间:2010-02-18 22:31:11

标签: sql-server

我必须在sql server中跟随表:

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中执行此操作的最佳方法是什么?

6 个答案:

答案 0 :(得分:2)

好的,首先......

你提到10分钟并提供一个15分钟的例子。另外你的样本数据应该返回与你发布的结果不同的结果..

解决方案使用Pivot

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

答案 1 :(得分: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)

答案 2 :(得分: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

答案 3 :(得分: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

请注意,在您的数据中,您在时间段中的失败次数和确认次数相同。

答案 4 :(得分:0)

另一种选择......

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

答案 5 :(得分: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') 

*/

设置值和参数。我对所有内容进行了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

所以我的问题是:所提出的所有方法,随着数据量的增加,这些方法会更好地扩展?我希望有人测试一下。