我正在使用SQL Server 2008 R2,我有一个表:
tbl_calls
cl_Id
cl_StartDate
cl_endDate
我将两个参数@StartDate
和@EndDate
传递给我的存储过程。
我的要求是在每15分钟的持续时间之间计算记录数
示例:
@StartDate = '2015-11-16 00:00:00.000',
@EndDate = '2015-11-16 23:59:00.000'
输出应为:
Date Count
2015-11-16 00:00:00.000 10(Count of startDate between '2015-11-16 00:00:00.000' AND '2015-11-16 00:15:00.000')
2015-11-16 00:15:00.000 7(Count of startDate between '2015-11-16 00:15:00.000' AND '2015-11-16 00:30:00.000')
2015-11-16 00:30:00.000 50(Count of startDate between '2015-11-16 00:30:00.000' AND '2015-11-16 00:45:00.000')
upto @EndDate
我试图这样做,但没有想到,我不确定下面的查询是否在逻辑附近。
我尝试的是:
DECLARE @StartDate DATETIME = DATEADD(DAY,-1,GETUTCDATE()),
@EndDate DATETIME = GETUTCDATE()
SELECT New
FROM
(SELECT
(CASE
WHEN cl_StartTime BETWEEN @StartDate AND DATEADD(MINUTE, 15, @StartDate)
THEN 1
ELSE 0
END) AS New
FROM
tbl_Calls WITH (NOLOCK)
WHERE
cl_StartTime BETWEEN @StartDate AND @EndDate) AS Inners
GROUP BY
New
如果您需要更多详细信息,请与我们联系。
谢谢。
答案 0 :(得分:3)
首先,您需要生成从@StartDate
到@EndDate
的所有15分钟间隔。您可以在Tally Table.的帮助下执行此操作,然后在LEFT JOIN
上执行tbl_calls
来计算通话次数:
DECLARE @StartDate DATETIME = '2015-11-16 00:00:00.000',
@EndDate DATETIME = '2015-11-16 23:59:00.000'
DECLARE @nRows INT
SELECT @nRows = DATEDIFF(MINUTE, @StartDate, DATEADD(DAY, 1, CAST(@EndDate AS DATE))) / 15
;WITH E1(N) AS(
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b),
Tally(N) AS(
SELECT TOP(@nRows)
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM E8
),
Intervals(sd, ed) AS(
SELECT
DATEADD(MINUTE, (t.N - 1) * 15, @StartDate),
DATEADD(MINUTE, N * 15, @StartDate)
FROM Tally t
)
SELECT
i.sd, i.ed, cnt = COUNT(c.cl_Id)
FROM Intervals i
LEFT JOIN tbl_calls c
ON i.sd <= c.cl_EndDate
AND i.ed > c.cl_Startdate
GROUP BY i.sd, i.ed
请注意,此处生成的时间间隔为@StartDate
,直至@EndDate
+ 1天的开头,即从'2015-11-16 00:00:00.000'
到'2015-11-17 00:00:00.000'
。
此外,JOIN
条件指定呼叫持续时间必须在间隔开始和间隔结束之间,但间隔结束不得与呼叫重叠。持续时间。您可以看到此answer以获得更多解释。
您可以根据自己的喜好修改JOIN
条件,但这基本上就是要点。
答案 1 :(得分:0)
一种方法是创建一个包含所需插槽的表(请参阅下面的#slots)....
declare @start_date datetime = '2015-11-17'
select dateadd( minute, rn, '2015-11-17' ) as start_date
into #src
from (
select row_number() over( order by object_id ) - 1 as rn
from sys.columns
) as rn;
create index cl on #src ( start_date );
select dateadd( minute, 15 * rn, @start_date ) as slot_start
into #slots
from (
select row_number() over( order by object_id ) - 1 as rn
from sys.columns
) as rn;
select s.slot_start, count(*) as rows_in_slot
from #slots s
inner join #src d on d.start_date >= s.slot_start
and d.start_date < dateadd( minute, 15, s.slot_start )
group by s.slot_start
order by s.slot_start
答案 2 :(得分:0)
此方法生成一个日期列表,从开始日期开始,到结束日期结束,相隔15分钟(TableA)。它计算tbl_calls中落在15分钟内的所有记录并给出计数。
declare @startdate datetime; set @StartDate = '2015-11-16 00:00:00.000';
declare @EndDate datetime; set @EndDate = '2015-11-16 23:59:00.000';
WITH TableA (DateSlotStart, DateSlotEnd) AS (
SELECT dateadd(n, (number * 15), @StartDate) AS DateSlotStart
, dateadd(n, (number + 1) * 15, @StartDate) AS DateSlotEnd
FROM master.dbo.spt_values
WHERE name IS NULL and dateadd(n, (number) * 15, @StartDate) <= @EndDate
)
select DateSlotStart, DateSlotEnd, count(cl_Id) from tableA
left join @tbl_calls calls on calls.cl_StartDate >= DateSlotStart and calls.cl_StartDate < DateSlotEnd
group by DateSlotStart, DateSlotEnd
答案 3 :(得分:0)
和其他人一样,我建议创建一个保存间隔的表格。这将为您提供加入和GROUP BY所需的记录。
在我的示例中,我使用recursive CTE创建了一个间隔表。但是还有很多其他方法可以实现这一点,包括使用真正的物理表。我还在另一个CTE中创建了一些样本记录,所以任何人都可以运行这个例子。
如果你想查找没有打开票证的间隔,你可以使用OUTER JOIN重做这个例子。
DECLARE @StartTime SMALLDATETIME = '2015-01-01 09:00:00.000';
DECLARE @EndTime SMALLDATETIME = '2015-01-01 10:30:00.000';
WITH tbl_Calls AS
(
/* This CTE returns some sample records to help
* illistrate the princple.
* Each sample record has a start and end date
* between 9:00 and 10:30 on Jan 1st 2015.
*/
SELECT
r.*
FROM
(
VALUES
(1, '2015-01-01 09:00:00.000', '2015-01-01 09:30:00.000'),
(2, '2015-01-01 09:01:00.000', '2015-01-01 10:00:00.000'),
(3, '2015-01-01 09:02:00.000', '2015-01-01 10:15:00.000'),
(4, '2015-01-01 09:03:00.000', '2015-01-01 09:14:00.000'),
(5, '2015-01-01 09:15:00.000', '2015-01-01 09:16:00.000' ),
(6, '2015-01-01 09:16:00.000', '2015-01-01 10:30:00.000')
) AS r (cl_Id, cl_StartDate, cl_EndDate)
),
Interval AS
(
/* This CTE returns 1 record for each 15 min interval
* between the start and end time.
* PLEASE NOTE: This CTE uses recursion to generate the
* required records.
*/
SELECT
@StartTime AS IntervalStart,
DATEADD(MINUTE, 15, @StartTime) AS IntervalEnd
UNION ALL
SELECT
-- Addding a millisecond prevents overlapping intervals.
DATEADD(MILLISECOND, 1, IntervalEnd) AS IntervalStart,
DATEADD(MINUTE, 15, IntervalEnd) AS IntervalEnd
FROM
Interval
WHERE
IntervalEnd <= @EndTime
)
-- ******************************************************
-- The CTEs above this section exist only to provide
-- sample records.
-- The technique for banding date times is shown below.
-- ******************************************************
SELECT
i.IntervalStart,
COUNT(c.cl_Id) AS RecordsOpened
FROM
tbl_Calls AS c
INNER JOIN Interval AS i ON c.cl_StartDate >= i.IntervalStart
AND c.cl_StartDate < i.IntervalEnd
GROUP BY
i.IntervalStart
;