August 31, 2010 at 10:10 am
The powers that be have requested a report that essentially shows each support rep and the number of tickets per day for that rep. The catch is that they want the result set to include a zero count for the date if the rep worked no tickets.
So a report should look like this:
Date RepTickets
2010-08-01AFO0
2010-08-01AGT1
2010-08-01ISC2
2010-08-01ZPC1
2010-08-02AFO0
2010-08-02AGT1
2010-08-02ISC1
2010-08-02ZPC0
and so on...
Here is a script to create sample tables and populate them:
--Create the ticket header table
CREATE TABLE [dbo].[TicketHdr](
[TicketID] [int] NOT NULL,
[TicketDate] [datetime] NULL,
CONSTRAINT [PK_TicketHdr] PRIMARY KEY CLUSTERED
(
[TicketID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Create the ticket details table
CREATE TABLE [dbo].[TicketDtl](
[TicketID] [int] NOT NULL,
[Rep] [varchar](10) NULL,
CONSTRAINT [PK_TicketDtl] PRIMARY KEY CLUSTERED
(
[TicketID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Populate TicketHdr
INSERT INTO TicketHdr(TicketID, TicketDate)
VALUES (1, '2010-8-1'),
(2, '2010-8-1'),
(3, '2010-8-1'),
(4, '2010-8-1'),
(5, '2010-8-2'),
(6, '2010-8-2'),
(7, '2010-8-3'),
(8, '2010-8-3'),
(9, '2010-8-4'),
(10, '2010-8-5'),
(11, '2010-8-6'),
(12, '2010-8-7'),
(13, '2010-8-8'),
(14, '2010-8-8'),
(15, '2010-8-8'),
(16, '2010-8-8'),
(17, '2010-8-8'),
(18, '2010-8-9'),
(19, '2010-8-10'),
(20, '2010-8-11'),
(21, '2010-8-11'),
(22, '2010-8-11'),
(23, '2010-8-11'),
(24, '2010-8-11'),
(25, '2010-8-11'),
(26, '2010-8-11'),
(27, '2010-8-11'),
(28, '2010-8-11'),
(29, '2010-8-11'),
(30, '2010-8-11'),
(31, '2010-8-12'),
(32, '2010-8-12'),
(33, '2010-8-12'),
(34, '2010-8-12'),
(35, '2010-8-15'),
(36, '2010-8-15'),
(37, '2010-8-15'),
(38, '2010-8-15'),
(39, '2010-8-15'),
(40, '2010-8-16'),
(41, '2010-8-17'),
(42, '2010-8-17'),
(43, '2010-8-17'),
(44, '2010-8-18'),
(45, '2010-8-18'),
(46, '2010-8-18'),
(47, '2010-8-18'),
(48, '2010-8-19'),
(49, '2010-8-19')
--Populate TicketDtl
INSERT INTO TicketDtl(TicketID, Rep)
VALUES (1, 'ISC'),
(2, 'ZPC'),
(3, 'AGT'),
(4, 'ISC'),
(5, 'ISC'),
(6, 'AGT'),
(7, 'AFO'),
(8, 'ZPC'),
(9, 'ISC'),
(10, 'ISC'),
(11, 'ISC'),
(12, 'AGT'),
(13, 'ZPC'),
(14, 'AGT'),
(15, 'AFO'),
(16, 'AGT'),
(17, 'ZPC'),
(18, 'ISC'),
(19, 'ZPC'),
(20, 'AFO'),
(21, 'AGT'),
(22, 'ZPC'),
(23, 'AFO'),
(24, 'AGT'),
(25, 'ISC'),
(26, 'ISC'),
(27, 'ISC'),
(28, 'AGT'),
(29, 'AFO'),
(30, 'AGT'),
(31, 'ISC'),
(32, 'ISC'),
(33, 'ISC'),
(34, 'AGT'),
(35, 'AGT'),
(36, 'AFO'),
(37, 'AFO'),
(38, 'AFO'),
(39, 'ZPC'),
(40, 'ZPC'),
(41, 'ISC'),
(42, 'AGT'),
(43, 'ISC'),
(44, 'AGT'),
(45, 'AFO'),
(46, 'ISC'),
(47, 'AGT'),
(48, 'ZPC'),
(49, 'AFO')
I am hoping there is a simple solution to this, but am just not getting it.
Thansk!
Jerry
August 31, 2010 at 11:01 am
WITH Reps AS (
SELECT DISTINCT Rep
FROM TicketDtl)
SELECT h.TicketDate,
r.Rep,
COUNT(d.Rep)
FROM TicketHdr h
CROSS JOIN Reps r
LEFT OUTER JOIN TicketDtl d ON d.Rep = r.Rep AND d.TicketID=h.TicketID
GROUP BY h.TicketDate,r.Rep
ORDER BY h.TicketDate,r.Rep;
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537August 31, 2010 at 11:04 am
Wow! That did it! I knew it was simple, but just couldn't wrap my head around it.
Still learning about things like CROSS JOIN and CROSS APPLY!
Thanks a ton for the help!
August 31, 2010 at 11:18 am
lets say for example that were no tickets at all on 2010-08-02.....do you want to see all reps with a zero count?
________________________________________________________________
you can lead a user to data....but you cannot make them think
and remember....every day is a school day
August 31, 2010 at 11:20 am
Mark did a good job.
If you also need dates to show if there were zero tickets for all reps for that date, then you need to utilize a calendar table. This solution creates a virtual one based on the min/max ticket dates in the system.
-- declare and initialize the variables needed
DECLARE @MinDate datetime,
@MaxDate datetime,
@DateDiff int;
SELECT @MinDate = MIN(TicketDate),
@MaxDate = MAX(TicketDate)
FROM dbo.TicketHdr;
SET @DateDiff = DATEDIFF(day, @MinDate, @MaxDate);
-- See Jeff Moden's article
-- The "Numbers" or "Tally" Table: What it is and how it replaces a loop.
-- at http://www.sqlservercentral.com/articles/T-SQL/62867/.
-- NOTE! A permanent tally table will always be MUCH faster
-- than this inline one. See the above article to create your own!
;WITH
Tens (N) AS (SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL
SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL
SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0),
Thousands(N) AS (SELECT 1 FROM Tens t1 CROSS JOIN Tens t2 CROSS JOIN Tens t3),
Millions (N) AS (SELECT 1 FROM Thousands t1 CROSS JOIN Thousands t2),
Tally (N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM Millions),
-- get all dates between the two dates
Dates (TicketDate) AS (SELECT DateAdd(day, N-1, @MinDate) FROM Tally WHERE N <= @DateDiff+1),
-- get the distinct reps in the system
Reps AS (SELECT DISTINCT Rep FROM dbo.TicketDtl)
SELECT d.TicketDate,
r.Rep,
Tickets = COUNT(td.Rep)
FROM Dates d
CROSS JOIN Reps r
LEFT JOIN dbo.TicketHdr th
ON d.TicketDate = th.TicketDate
LEFT JOIN dbo.TicketDtl td
ON th.TicketID = td.TicketID
AND td.Rep = r.Rep
GROUP BY d.TicketDate, r.Rep
ORDER BY d.TicketDate, r.Rep
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
August 31, 2010 at 11:27 am
WayneS (8/31/2010)
Mark did a good job.If you also need dates to show if there were zero tickets for all reps for that date, then you need to utilize a calendar table. This solution creates a virtual one based on the min/max ticket dates in the system.
-- declare and initialize the variables needed
DECLARE @MinDate datetime,
@MaxDate datetime,
@DateDiff int;
SELECT @MinDate = MIN(TicketDate),
@MaxDate = MAX(TicketDate)
FROM dbo.TicketHdr;
SET @DateDiff = DATEDIFF(day, @MinDate, @MaxDate);
-- See Jeff Moden's article
-- The "Numbers" or "Tally" Table: What it is and how it replaces a loop.
-- at http://www.sqlservercentral.com/articles/T-SQL/62867/.
-- NOTE! A permanent tally table will always be MUCH faster
-- than this inline one. See the above article to create your own!
;WITH
Tens (N) AS (SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL
SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL
SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0 UNION ALL SELECT 0),
Thousands(N) AS (SELECT 1 FROM Tens t1 CROSS JOIN Tens t2 CROSS JOIN Tens t3),
Millions (N) AS (SELECT 1 FROM Thousands t1 CROSS JOIN Thousands t2),
Tally (N) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM Millions),
-- get all dates between the two dates
Dates (TicketDate) AS (SELECT DateAdd(day, N-1, @MinDate) FROM Tally WHERE N <= @DateDiff+1),
-- get the distinct reps in the system
Reps AS (SELECT DISTINCT Rep FROM dbo.TicketDtl)
SELECT d.TicketDate,
r.Rep,
Tickets = COUNT(td.Rep)
FROM Dates d
CROSS JOIN Reps r
LEFT JOIN dbo.TicketHdr th
ON d.TicketDate = th.TicketDate
LEFT JOIN dbo.TicketDtl td
ON th.TicketID = td.TicketID
AND td.Rep = r.Rep
GROUP BY d.TicketDate, r.Rep
ORDER BY d.TicketDate, r.Rep
Also with an inline tally table, a million is a bit much for this sort of data. Ten thousand would probably do.
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537August 31, 2010 at 11:52 am
Hadn't thought of that yet. Will probably use your additions to the script just in case.
Thanks!
August 31, 2010 at 12:15 pm
Mark-101232 (8/31/2010)
Also with an inline tally table, a million is a bit much for this sort of data. Ten thousand would probably do.
Probably right. I just have the million-row virtual tally table stored as a SQL Snippet (from www.ssmstoolspack.com), and just always use it. The code does restrict it's use to just the rows it actually needs.
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
Viewing 8 posts - 1 through 7 (of 7 total)
You must be logged in to reply to this topic. Login to reply