我必须在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中执行此操作的最佳方法是什么?
答案 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
所以我的问题是:所提出的所有方法,随着数据量的增加,这些方法会更好地扩展?我希望有人测试一下。