Pivot table between two dates using SQL Server 2008 R2 - sql-server

I have the following table:
Example:
create table test
(
col_dt1 date,
col_dt2 date
)
Inserting some records:
insert into test values('2014-11-07','2014-12-01');
select * from test;
col_dt1 col_dt2
----------------------
2014-11-07 2014-12-01
Expected Result:
col_dt1 col_dt2 07 November 2014 08 November 2014 .................... 01 December 2014
-----------------------------------------------------------------------------------------------
2014-11-07 2014-12-01 1 0 .................... 1
I got stuck to get all dates between two dates to have the stuff column in pivot table.

DECLARE #Start_Date DATE, #End_Date DATE, #QUERY NVARCHAR(MAX), #SUBQUERY NVARCHAR(MAX), #ROWCOUNT int
CREATE TABLE #TempTable(
ID int IDENTITY(1,1) NOT NULL,
Start_Date date,
End_Date date,
Dates NVARCHAR(50),
HasDate int
)
CREATE TABLE #TempTable2(
Start_Date date,
End_Date date,
Dates NVARCHAR(50),
HasDate int
)
SET #Start_Date = (SELECT TOP 1 col_dt1 from test)
SET #End_Date = (SELECT TOP 1 col_dt2 from test)
INSERT INTO #TempTable
SELECT
#Start_Date as Start_Date,
#End_Date as End_Date,
RIGHT(REPLICATE('0', DAY(DATEADD(DAY,number,#Start_Date))) + CAST(DAY(DATEADD(DAY,number,#Start_Date)) AS NVARCHAR(2)), 2)
+' '+DATENAME(MONTH,DATEADD(DAY,number,#Start_Date))+' '+CONVERT(NVARCHAR(50),YEAR(DATEADD(DAY,number,#Start_Date))) as Start_Date,
HasDate =
CASE
WHEN DATEADD(DAY,number,#Start_Date)=#Start_Date THEN 1
WHEN DATEADD(DAY,number,#Start_Date)=#End_Date THEN 1
ELSE 0
END
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY,number,#Start_Date) <= #End_Date
INSERT INTO #TempTable2 SELECT [Start_Date],[End_Date],[Dates],HasDate FROM #TempTable
SELECT * FROM #TempTable
SET #QUERY=''
SET #QUERY+='SELECT * FROM #TempTable2
PIVOT
(
Max(HasDate)
FOR Dates IN ('
SET #SUBQUERY=''
SET #ROWCOUNT=1
WHILE #ROWCOUNT <= (SELECT COUNT(*) FROM #TempTable)
BEGIN
SET #SUBQUERY=#SUBQUERY+'['+(SELECT CONVERT(NVARCHAR(50),Dates)as Dates FROM #TempTable WHERE ID=#ROWCOUNT)+']'
IF (#ROWCOUNT<>(SELECT COUNT(*) FROM #TempTable))
BEGIN
SET #SUBQUERY=#SUBQUERY+','
END
SET #ROWCOUNT=#ROWCOUNT+1
END
SET #QUERY=#QUERY+#SUBQUERY+')
)AS tblPivot'
PRINT(#QUERY)
EXECUTE(#QUERY)
DROP TABLE #TempTable
DROP TABLE #TempTable2
You can try this.

Related

Stored procedure to add 30 days using DATEDIFF within while loop condition in Date Dimension table

I want to add 30 consecutive days of data in my Date Dimension table using DATEDIFF() but I am getting blank result. Can you please help me correct the code below to get the desired result?
CREATE TABLE dbo.dateDimension (
DateKey INT NOT NULL
,DateValue DATE NOT NULL
,CYear SMALLINT NOT NULL
,CMonth TINYINT NOT NULL
,CONSTRAINT PK_DimDate PRIMARY KEY ( DateKey )
);
GO
CREATE PROC dbo.dateTest
#StartDate DATETIME
AS
WHILE (DATEDIFF(day, #StartDate, GETDATE()) <=30)
BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
,#StartDate
,YEAR(#StartDate)
,MONTH(#StartDate)
SET #StartDate = DATEADD(d,1,#StartDate)
END;
GO
EXECUTE dbo.dateTest '2010-01-01'
SELECT * FROM dbo.dateDimension
The issue is that this logic:
DATEDIFF(day, #StartDate, GETDATE())
gives 3739 days with your current start date, so its never less than 30. Personally I would simply count it as follows:
DECLARE #StartDate DATETIME = '2010-01-01', #Count INT = 0;
WHILE #Count <= 30 BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
, #StartDate
, YEAR(#StartDate)
, MONTH(#StartDate);
SET #StartDate = DATEADD(d,1,#StartDate);
set #Count = #Count + 1;
END;
SELECT *
FROM dbo.dateDimension;
If you are using SQL Server 2016 or above, this solution will not use a while loop, instead it uses a CTE to generate 30 rows numbered I to 30 and then uses the date to convert to yyyymmdd.
DECLARE #NUM_DAYS INT=30;
DECLARE #STARTDATE DATETIME='2020-01-01';
WITH CTE AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SRL
FROM STRING_SPLIT(REPLICATE(',',#num_days-1), ',') AS A
)
INSERT INTO dbo.dateDimension
SELECT
CONVERT(INT, CONVERT(CHAR(8), DATEADD(DAY, SRL-1, #STARTDATE), 112))
, #STARTDATE
, YEAR(#STARTDATE)
, MONTH(#STARTDATE)
FROM CTE
SELECT * FROM dbo.dateDimension

COUNT monthly sales for every year

I need to check monthly sales (count not sum) by area for long ranges of dates (5+ years), something like an Excel pivot table, currently I'm working it on Pandas but nobody here works with it so I'm trying to generate a view or a stored procedure in SQLServer for anyone who requires it. In this table sales are stored associated to an area and which product was.
I'm able to list and group AREA, SALES, MONTH AND YEAR, but as I mentioned, it would be easier to read if months or years where vertically aligned (there is about 100k records yearly and Excel lags at that point).
CREATE TABLE SALESHS
(
IDAREA INT,
DATEREG [NVARCHAR](50) NOT NULL,
IDPROD [NVARCHAR](50) NOT NULL
);
GO
-- Insert rows into table 'SALESHS'
INSERT INTO SALESHS
(
IDAREA, DATEREG, IDPROD
)
VALUES
(
1, '12/03/2019', 'xplpc'
),
(
1, '15/03/2019', 'ndtlctm'
),
(
2, '12/04/2019', 'wntd'
)
GO
SELECT IDAREA,
COUNT(IDAREA) AS CANT,
DATEREG, --DATE AS DD/MM/YYYY
DATEPART(MM,CAST(DATEREG AS DATETIME)) AS MONTH,
DATEPART(YYYY,CAST(DATEREG AS DATETIME)) AS YEAR,
FROM saleshs
WHERE DATEREG > 201712
GROUP BY DATEREG , idarea
ORDER BY DATEREG
Which returns this:
IDAREA AMOUNT MONTH YEAR PER_PRO
----------------------------------------
1 2 03 2019 201904
2 1 04 2019 201904
Expected results:
IDAREA JAN2019 FEB2019 MAR2019 APR2019
--------------------------------------
1 0 0 2 0
2 0 0 0 1
I know the basics of SQL and I don't expect a full answer either, but anything that could help me build this view it's appreciated. I've tried PIVOT also but I can't count, distinct and sum in the same query.
You can try Conditional Aggregation
SELECT IDAREA,
SUM( CASE WHEN YEAR(CAST(DATEREG AS DATETIME))= 2019 AND
MONTH(CAST(DATEREG AS DATETIME))=1 THEN
1
ELSE
0
END) JAN2019,
SUM( CASE WHEN YEAR(CAST(DATEREG AS DATETIME))= 2019 AND
MONTH(CAST(DATEREG AS DATETIME))=2 THEN
1
ELSE
0
END) FEB2019,
SUM( CASE WHEN YEAR(CAST(DATEREG AS DATETIME))= 2019 AND
MONTH(CAST(DATEREG AS DATETIME))=3 THEN
1
ELSE
0
END) MAR2019,
SUM( CASE WHEN YEAR(CAST(DATEREG AS DATETIME))= 2019 AND
MONTH(CAST(DATEREG AS DATETIME))=4 THEN
1
ELSE
0
END) APR2019
FROM saleshs
WHERE YEAR(CAST(DATEREG AS DATETIME))> 2017
GROUP BY IDAREA
ORDER BY IDAREA
Demo
--Build the column names for Pivot using dynamic SQL
DECLARE #YourChoice date
set #YourChoice = '2017/12/13' --change here to what date you want the earliest
declare #count int = 0
declare #columnstr varchar(max)
declare #columnpivot varchar(max)
declare #onecolumnname varchar(20)
set #columnstr = ''
set #columnpivot = ''
set #onecolumnname = ''
while #count <= DATEDIFF(MONTH,#YourChoice,GETDATE())
begin
set #onecolumnname = concat(cast(datename(month,dateadd(month,#count,#YourChoice)) as varchar(50)),cast(year(dateadd(month,#count,#YourChoice)) as varchar(10)))
set #columnstr = #columnstr + 'coalesce([' + #onecolumnname+ '],0) as '+#onecolumnname+', '
set #columnpivot = #columnpivot + '['+#onecolumnname+'], '
set #count = #count + 1
end
set #columnstr = left(#columnstr,len(#columnstr)-1)
set #columnpivot = '('+left(#columnpivot,len(#columnpivot)-1)+')'
--Pivot time!
declare #str varchar(max)
set #str =
'select IDAREA,' + #columnstr +' from (
select count(s.idarea) as amount,IDAREA,columnname from (
select *,datename(month,cast(substring(datereg,7,4)+''-''+substring(datereg,4,2)+''-''+substring(datereg,1,2) as datetime)) + SUBSTRING(datereg,7,4) as columnname
from SALESHS )s
group by IDAREA,columnname)s1
pivot
(
max(s1.amount)
for s1.columnname in '+#columnpivot+'
) p'
exec (#str)
Test Result 1 ('2017/12/13'):
DB<>Fiddle
Test Result 2 ('2018/12/14'):
DB<>Fiddle
I have created a Dynamic SQL to solve this particular issue. Query can be adjusted on which YEAR to display in the result and which Column to count in the PIVOT Section of the query. Date format in the i have used is below query MM/DD/YYYY.
You can run the code HERE
Below is the SQL Query.
CREATE TABLE SALESHS
( IDAREA INT,
DATEREG date NOT NULL,
IDPROD [NVARCHAR](50) NOT NULL
);
/* Insert rows into table 'SALESHS' */
INSERT INTO SALESHS
( IDAREA, DATEREG, IDPROD)
VALUES
( 1, '03/12/2019', 'xplpc'),
( 1, '03/15/2019', 'ndtlctm'),
( 2, '04/12/2019', 'wntd')
/* Create Calendar Table to capture all the dates for first day of month from start Date to end date */
CREATE TABLE Calendar
(
[CalendarDate] DATE
,[MonthName] AS FORMAT(CONVERT(DATE, DATEADD(m, DATEDIFF(m, 0, CalendarDate), 0)), 'MMM-yyyy')
,[MonthNo] AS FORMAT(CalendarDate,'MM')
,[Year] AS FORMAT(CalendarDate,'yyyy')
,DateKey AS CONCAT(FORMAT(CalendarDate,'yyyy'), FORMAT(CalendarDate,'MM'))
)
DECLARE #Date DATE, #StartDate DATE, #EndDate DATE
SET #Date = '01/01/2012'
SET #StartDate = CONVERT(DATE, DATEADD(m, DATEDIFF(m, 0, #Date), 0)) /* Set Start date to first day of the month for given date */
SET #EndDate = '04/01/2019'
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO Calendar (CalendarDate)
SELECT #StartDate
SET #StartDate = DATEADD(m, 1, #StartDate)
END
/* Variable to hold unique Months to be used in PIVOT clause */
DECLARE #UniqueMonthsToPivot NVARCHAR(MAX) = N''
/* Extract unique Month names with pivot formattings */
SELECT #UniqueMonthsToPivot = #UniqueMonthsToPivot + ', [' + COALESCE(MonthName, '') + ']'
FROM (SELECT DISTINCT MonthName FROM Calendar) DT
/* Remove first comma and space */
SELECT #UniqueMonthsToPivot = LTRIM(STUFF(#UniqueMonthsToPivot, 1, 1, ''))
/* Variable to hold pivot column names with alias to be used in SELECT Clause */
DECLARE #PivotMonthsToSelect NVARCHAR(MAX) = N''
/* Generate column names list for SELECT list with SUM Function and NULL handling.
YEAR in the where condition can be adjust to select and show only certain year or month in Select list.
Order by CalendarDate is important to define the sequence of columns in the result */
SELECT #PivotMonthsToSelect = #PivotMonthsToSelect + ', SUM(ISNULL([' + COALESCE(MonthName, '') + '], 0)) AS [' + MonthName + ']'
FROM Calendar WHERE Year >= 2012
Order by CalendarDate
/* Variable to hold t-sql query */
DECLARE #SQLStatement NVARCHAR(MAX) = N''
/* Generate dynamic PIVOT query here */
SET #SQLStatement =
N'SELECT IDAREA'
+ #PivotMonthsToSelect +
'FROM (
SELECT *
,CASE WHEN IDAREA IS NULL THEN 0 ELSE 1 END AS IDAREA_Dup
FROM Calendar C
LEFT JOIN SALESHS S ON C.CalendarDate = CONVERT(DATE, DATEADD(m, DATEDIFF(m, 0, DATEREG), 0))
) AA
PIVOT
( SUM(IDAREA_Dup)
FOR MonthName IN ('+ #UniqueMonthsToPivot +')
) P
WHERE IDAREA IS NOT NULL
GROUP BY IDAREA
'
/* Check the generated dynamic t-sql PIVOT query below */
--PRINT (#SQLStatement)
/* Execute the generated dynamic t-sql PIVOT query below */
EXEC (#SQLStatement)

Calculate Annual Leaves for All employees and return more than one column in SQL Server

The following procedure calculates annual leaves of employees based on the provided empid. First Question: How can I create/modify this procedure to calculate annual leaves for all employees. Second Question: Return more columns like empname, designation, annual leave balance? please note that i am using sql server 2016 community edition.
ALTER proc [dbo].[spAvailalbeAL](#empID int)
as
begin
declare #StartDate datetime
declare #totMonths int
declare #aAnnualLeaves int
declare #avlAL int
set #avlAL = (select sum(Availed) from LeaveDetails where empid = #empID AND TypeID=3)
if ( #avlAL IS NULL)
begin
set #StartDate = '2017-07-01'
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)
select #aAnnualLeaves
end
else
begin
set #StartDate = '2017-07-01'
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)-#avlAL
select #aAnnualLeaves
end
end
For showing all employees you can pass 0 or Null for #empid parameter and then you can create Temporary Table like
CREATE TABLE #LeaveDetails(EmpID INT,TotalALAvailed INT)
then fill the table
INSERT INTO #LeaveDetails(EmpID,TotalALAvailed) SELECT EmpID,SUM(Availed) FROM LeaveDetails WHERE (EmpID=#EmpID OR #EmpID=0) AND Type=3 GROUP BY EmpID
You can select all required columns in last Select statement.
You need something like this:
Create proc [dbo].[spAvailalbeAL]
as
begin
declare #StartDate datetime = '2017-07-01'
declare #totMonths int
declare #aAnnualLeaves int
set #totMonths = (SELECT DATEDIFF(mm, #StartDate, GETDATE()))
print #totMonths
set #aAnnualLeaves = 2
set #aAnnualLeaves = (#aAnnualLeaves*#totMonths)
print #aAnnualLeaves
SELECT distinct e.EMPLOYEE_NAME,e.desg_cd,sum(isnull(ea.Availed,0)) over ( partition by e.EmpID ),#aAnnualLeaves - sum(isnull(ea.Availed,0)) over ( partition by e.EmpID ) as leaves
from Employee e
inner join LeaveDetails ea
on e.EMPLOYEE_CD = ea.EMPLOYEE_CD
where DATE > #StartDate
AND ea.TypeID=3
end
-- exec spAvailalbeAL

Pivot Activity Code Days Months

I am trying to get the activity codes for specific days to show the 31 days in every month of the year for a specific staff member.
If the staff member was present, sick, holiday leave, etc... I want those activity codes to display based on the output below for a year act_date range.
Thanks!
Pivot Activity Code Days Months
This can be achieved with pivoting. Here you can enter the staff id in the query to fetch the results for that particular staff.
--create table
create table staff_info
(
staffId int,
actDate datetime,
activityCode int
)
--insert values
insert into staff_info values
(2699, '01/02/2017', 101),
(2699, '05/14/2017', 303),
(2699, '08/06/2017', 101),
(1927, '10/25/2017', 105)
--actual solution
select * from
(
select staffId, day(actDate) as act_day,month(actDate) as actual_month,
activityCode
from staff_info
where staffId=2699 ----- enter the staff id here
) src
pivot
(
sum(activityCode)
for act_day in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],
[14],[15],
[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],
[31]
)
) p
Result:
Firstly, create a function which would give the date values for a specific range
CREATE FUNCTION [dbo].[GetAllDatesBetweenRange]
(
#FromDate DATE
,#ToDate DATE
)
RETURNS #Dates TABLE
(
DateVal DATE
)
AS
BEGIN
;WITH CTE
AS
(
SELECT #FromDate AS FromDate
UNION ALL
SELECT DATEADD(DD,1,FromDate)
FROM CTE
WHERE FromDate < #ToDate
)
INSERT INTO #Dates
SELECT FromDate FROM CTE
OPTION (MAXRECURSION 0)
RETURN;
END
GO
Use the below dynamic query to pivot for the specific date range
DECLARE #Sql NVARCHAR(MAX);
DECLARE #DateVal NVARCHAR(MAX);
SELECT #DateVal = STUFF((SELECT ',['+CAST(DateVal AS NVARCHAR(50))+']'
FROM [dbo].[GetAllDatesBetweenRange]('2017-01-01','2017-12-31')
FOR XML PATH('')),1,1,'')
SET #Sql = '
;WITH CTE
AS
(
SELECT Res1.STAFF_ID
,Res2.DateVal
,Res1.ACTIVITY_CODE
FROM [dbo].[GetAllDatesBetweenRange](''''2017-01-01'''',''''2017-12-31'''') Res1
LEFT JOIN TableA A ON A.ACT_DATE = Res1.DateVal
)
SELECT STAFF_ID
,*
FROM CTE
PIVOT
(
MAX(ACTIVITY_CODE)
FOR DateVal IN ('+#DateVal+')'+'
)'
EXEC SP_EXECUTESQL #Sql

SQL Server related question

I have this thing that i need to do and some advices will be greatly appreciated.
I have a SQL server table with some phone calls.For each phone call i have the start and end time.
What i need to accomplish: a stored procedure which for a certain period of time, let's say 5 hours at a x interval, lets say 2 minutes returns the number of connected calls.
Something like:
Interval Nr of Calls Connected
01-01-2010 12:00:00 - 01-01-2010 12:05:00 30
01-01-2010 12:05:01 - 01-01-2010 12:10:00 10
.............
Which will be the fastest way to do that? Thank you for your help
This will work for intervals that have calls ...
Declare #datetimestart datetime
Declare #interval int
Set #datetimestart = '2009-01-01 12:00:00'
Set #interval = 5 --in minutes
Select
[start_interval], [end_interval] , count([start_interval]) as [calls]
From
(
Select
DateAdd( Minute,Floor(DateDiff(Minute,#datetimestart,[date])/#interval)*#interval
,#datetimestart) ,
DateAdd( Minute,#interval + Floor(DateDiff(Minute,#datetimestart,[date])/#interval)*#interval
,#datetimestart)
From yourTable
) As W([start_interval],[end_interval])
group by [start_interval], [end_interval]
This will work for all intervals regardless of number of calls..
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 yourtable)
SET #datetimecurrent = #datetimestart
declare #temp as table ([start_interval] datetime, [end_interval] datetime)
while #datetimecurrent < #datetimeend
BEGIN
insert into #temp select (#datetimecurrent), dateAdd( minute, #interval, #datetimecurrent)
set #datetimecurrent = dateAdd( minute, #interval, #datetimecurrent)
END
Select
*
From
(
Select
[start_interval],[end_interval], count(d.[start_time])
From #temp t left join yourtable d on d.[start_time] between t.[start_interval] and t.[end_interval]
) As W([start_interval],[end_interval], [calls])
I Altered Gaby's example a little to do What you expected
Declare #datetimeend datetime
,#datetimecurrent datetime
,#interval int
Set #interval = 10
Set #datetimeend = (Select max([end_time]) from Calls)
SET #datetimecurrent = '2010-04-17 14:20:00'
declare #temp as table ([start_interval] datetime, [end_interval] datetime)
while #datetimecurrent < #datetimeend
BEGIN
insert into #temp select (#datetimecurrent), dateAdd( minute, #interval, #datetimecurrent)
set #datetimecurrent = dateAdd( minute, #interval, #datetimecurrent)
END
Select
[start_interval],[end_interval], count(d.id) [COUNT]
From #temp t
left join Calls d on
d.end_time >= t.start_interval
AND d.start_time <= t.end_interval
GROUP BY [start_interval],[end_interval]
used this to create the table and fill it
CREATE TABLE dbo.Calls
(
id int NOT NULL IDENTITY (1, 1),
start_time datetime NOT NULL,
end_time datetime NULL,
caller nvarchar(50) NULL,
receiver nvarchar(50) NULL
) ON [PRIMARY]
GO
ALTER TABLE dbo.Calls ADD CONSTRAINT
PK_Calls PRIMARY KEY CLUSTERED
(
id
) ON [PRIMARY]
GO
DECLARE #I INT
SET #I = 0
WHILE #I < 100
BEGIN
INSERT INTO Calls
(start_time, end_time)
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-10,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-9,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-9,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-8,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-8,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-7,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-7,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-6,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-6,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-5,GETDATE()))
UNION
SELECT
DATEADD(HOUR,-#I,DATEADD(MINUTE,-5,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-4,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-4,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-3,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-3,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-2,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-2,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-1,GETDATE()))
UNION
select
DATEADD(HOUR,-#I,DATEADD(MINUTE,-1,GETDATE()))
,DATEADD(HOUR,-#I,DATEADD(MINUTE,-0,GETDATE()));
SET #I = #I + 1
END
Done in SQL Server 2008
but the script would work in other versions
I would use a Numbers pivot table to get the time intervals and then count all calls which overlapped the interval:
SELECT Intervals.IntervalStart
,Intervals.IntervalEnd
,COUNT(*)
FROM (
SELECT DATEADD(MINUTE, Numbers * 2, #StartTime) AS IntervalStart
,DATEADD(MINUTE, (Numbers + 1) * 2, #StartTime) AS IntervalEnd
FROM Numbers
WHERE Numbers BETWEEN 0 AND (5 * 60 / 2)
) AS Intervals
LEFT JOIN Calls
ON Calls.CallEnd >= Intervals.IntervalStart
AND Calls.CallStart < Intervals.IntervalEnd
GROUP BY Intervals.IntervalStart
,Intervals.IntervalEnd
To get the empty intervals, you would need to LEFT JOIN to this from another "Intervals" derived table.
How about this approach:
select Year(StartTime) as Year, Month(StartTime) as Month, Day(StartTime) as Day, datepart(hh, StartTime) as Hour, datepart(mm, StartTime) / 2 as TwoMinuteSegment, count(*)
from MyTable
where StartDate between '01-01-2010 12:00:00' and '01-01-2010 17:00:00'
group by Year(StartTime), Month(StartTime), Day(StartTime), datepart(hh, StartTime), datepart(mm, StartTime) / 2

Resources