Sum Value if Two Specific Values Occur on the Same Day - tsql

I've got a dataset that has species' harvest by weapon type by dates. Data set example below:
Species Total HarvestMonthDayYear WeaponID WeaponType
Deer 623 1/14/2017 1 Gun
Deer 10 1/14/2017 3 Reg Bow
Deer 15 1/14/2017 4 Crossbow
Deer 5 9/20/2017 4 Crossbow
Deer 9 9/21/2017 2 Muzzleloader
Deer 2 9/21/2017 3 Reg Bow
Deer 1 9/21/2017 4 Crossbow
Deer 1 9/21/2017 8 Shotgun
Deer 10 9/22/2017 1 Gun
Deer 1 9/22/2017 3 Reg Bow
What I would to accomplish is that when "Reg Bow" and "Crossbow" harvest on the same day, I would like to combine the results into one row named "Archery". And the final data set should look like:
Species Total HarvestMonthDayYear WeaponID WeaponType
Deer 623 1/14/2017 1 Gun
Deer 25 1/14/2017 10 Archery
Deer 5 9/20/2017 4 Crossbow
Deer 9 9/21/2017 2 Muzzleloader
Deer 3 9/21/2017 10 Archery
Deer 1 9/21/2017 8 Shotgun
Deer 10 9/22/2017 1 Gun
Deer 1 9/22/2017 2 Muzzleloader
Deer 1 9/22/2017 3 Reg Bow
On 01/14/2017 and 09/22/2017 - a regular bow and crossbow were used to harvest deer so I would like to combine those into one set - but on 09/20/2017 and 09/22/2017 - only a crossbow or regular bow was used so this result should be left as it.
Is this possible? I cannot think of a way to even begin to code this out.

You could phrase this as a union:
WITH cte AS (
SELECT Species, HarvestMonthDayYear, SUM(Total) AS Total
FROM yourTable
WHERE
WeaponType IN ('Reg Bow', 'Crossbow')
GROUP BY
Species, HarvestMonthDayYear
HAVING COUNT(DISTINCT WeaponType) = 2
)
SELECT
t1.Species, t1.Total, t1.HarvestMonthDayYear, t1.WeaponID, t1.WeaponType
FROM yourTable t1
LEFT JOIN cte t2
ON t1.Species = t2.Species AND
t1.HarvestMonthDayYear = t2.HarvestMonthDayYear
WHERE
t2.Species IS NULL OR
(t2.Species IS NOT NULL AND WeaponType NOT IN ('Reg Bow', 'Crossbow'))
UNION ALL
SELECT
Species, Total, HarvestMonthDayYear, 10, 'Archery'
FROM cte;
Demo here:
Rextester

Without TCE :
SELECT Species, HarvestMonthDayYear, SUM(Total) AS Total
, CASE WHEN WeaponType IN ('Reg Bow', 'Crossbow') THEN 10 ELSE WeaponID END AS WeaponID
, MAX(CASE WHEN WeaponType IN ('Reg Bow', 'Crossbow') THEN 'Archery' ELSE WeaponType END) AS WeaponType
FROM yourTable
GROUP BY
Species, HarvestMonthDayYear
, (CASE WHEN WeaponType IN ('Reg Bow', 'Crossbow') THEN 10 ELSE WeaponID END)

This should give you what you need, uses CTE but no UNION (tested) and is slightly more performant...
WITH HarvestResults AS
(
SELECT Species,
Total,
HarvestMonthDayYear,
CASE WHEN WeaponType IN ('Crossbow','Reg Bow') THEN 10 ELSE WeaponID END AS WeaponID,
WeaponType,
LAG(HarvestMonthDayYear,1) OVER(ORDER BY Species,HarvestMonthDayYear) AS PrevHarvestDate,
LEAD(HarvestMonthDayYear,1) OVER(ORDER BY Species,HarvestMonthDayYear) AS NextHarvestDate,
LAG(WeaponType,1) OVER(ORDER BY Species,HarvestMonthDayYear) AS PrevWeaponType,
LEAD(WeaponType,1) OVER(ORDER BY Species,HarvestMonthDayYear) AS NextWeponType
FROM dbo.Harvest
)
SELECT Species,
SUM(Total) AS TOTAL,
HarvestMonthDayYear,
CASE WHEN WeaponType IN ('Crossbow','Reg Bow')
AND ((PrevHarvestDate = HarvestMonthDayYear OR NextHarvestDate = HarvestMonthDayYear)
AND (PrevWeaponType IN ('Crossbow','Reg Bow') OR NextWeponType IN ('Crossbow','Reg Bow')))
THEN 10 ELSE WeaponID END AS WeaponID,
CASE WHEN WeaponType IN ('Crossbow','Reg Bow')
AND ((PrevHarvestDate = HarvestMonthDayYear OR NextHarvestDate = HarvestMonthDayYear)
AND (PrevWeaponType IN ('Crossbow','Reg Bow') OR NextWeponType IN ('Crossbow','Reg Bow')))
THEN 'Archery' ELSE WeaponType END AS WeaponType
FROM HarvestResults
GROUP BY Species,
HarvestMonthDayYear,
CASE WHEN WeaponType IN ('Crossbow','Reg Bow')
AND ((PrevHarvestDate = HarvestMonthDayYear OR NextHarvestDate = HarvestMonthDayYear)
AND (PrevWeaponType IN ('Crossbow','Reg Bow') OR NextWeponType IN ('Crossbow','Reg Bow')))
THEN 10 ELSE WeaponID END,
CASE WHEN WeaponType IN ('Crossbow','Reg Bow')
AND ((PrevHarvestDate = HarvestMonthDayYear OR NextHarvestDate = HarvestMonthDayYear)
AND (PrevWeaponType IN ('Crossbow','Reg Bow') OR NextWeponType IN ('Crossbow','Reg Bow')))
THEN 'Archery' ELSE WeaponType END
ORDER BY Species,
HarvestMonthDayYear,
WeaponID,
WeaponType;

Related

Parse custom tags In TSql

I have the following data in the csv and want to parse the tag elements to get the column and values from the tag.
1,{
"StudentLocs":["US","Kric"],
"Student_Service":["NY Volunteer"],
"Student_Unit":["Band1"],
"Student_enZone":["UTC"],
"Student_Geoloc":["Ind"],
"StudentRegisted":[FT"],
"StudentGender":["Male"],
"StudentName":["Sam"]
}
Expected output:
StudentId SLocs SService SUnit SenZone SGeoloc SRegisted SGender SName
1 US,Kric NY Volunteer Band1 UTC Ind FT Male Sam
Thanks for your help in advance !
For this you can use DelimitedSplit8K.
Against a single value:
DECLARE #string VARCHAR(8000) =
'1,{
"StudentLocs":["US","Kric"],
"Student_Service":["NY Volunteer"],
"Student_Unit":["Band1"],
"Student_enZone":["UTC"],
"Student_Geoloc":["Ind"],
"StudentRegisted":[FT"],
"StudentGender":["Male"],
"StudentName":["Sam"]
}';
SELECT
StudentId = MAX(CASE split.RN WHEN 0 THEN split.String END),
SLocs = MAX(CASE split.RN WHEN 2 THEN split.String END),
SService = MAX(CASE split.RN WHEN 3 THEN split.String END),
SUnit = MAX(CASE split.RN WHEN 4 THEN split.String END),
SenZone = MAX(CASE split.RN WHEN 5 THEN split.String END),
SGeoloc = MAX(CASE split.RN WHEN 6 THEN split.String END),
SRegisted = MAX(CASE split.RN WHEN 7 THEN split.String END),
SGender = MAX(CASE split.RN WHEN 8 THEN split.String END),
SName = MAX(CASE split.RN WHEN 9 THEN split.String END)
FROM
(
SELECT RN = 0, String = SUBSTRING(#string,1,CHARINDEX(',',#String)-1)
UNION ALL
SELECT s.ItemNumber, clean.string
FROM (VALUES(#string,CHARINDEX(',',#string))) AS f(String,B)
CROSS APPLY dbo.DelimitedSplit8K(f.String,CHAR(10)) AS s
CROSS APPLY (VALUES(CHARINDEX('":',s.item))) AS d(Pos)
CROSS APPLY (VALUES(CHARINDEX(CHAR(13),s.item))) AS v(E)
CROSS APPLY (VALUES(REPLACE(SUBSTRING(
s.item,d.Pos+3,v.E-d.Pos-5),'"',''))) AS clean(String)
WHERE d.Pos > 0
) AS split;
Returns:
SomeId StudentId SLocs SService SUnit SenZone SGeoloc SRegisted SGender SName
----------- ------------- ------------ --------------- ------ -------- -------- ---------- -------- ---------
1 1 US,Kric NY Volunteer Band1 UTC Ind FT Male Sam
Against a table:
-- Sample table
DECLARE #table TABLE (SomeId INT IDENTITY, String VARCHAR(8000));
INSERT #table (String) VALUES(
'1,{
"StudentLocs":["US","Kric"],
"Student_Service":["NY Volunteer"],
"Student_Unit":["Band1"],
"Student_enZone":["UTC"],
"Student_Geoloc":["Ind"],
"StudentRegisted":[FT"],
"StudentGender":["Male"],
"StudentName":["Sam"]
}'),
('1,{
"StudentLocs":["US","Chicago"],
"Student_Service":["Rock Star"],
"Student_Unit":["Band4"],
"Student_enZone":["XFS"],
"Student_Geoloc":["Ill"],
"StudentRegisted":[PT"],
"StudentGender":["Female"],
"StudentName":["Juliana"]
}');
SELECT t.SomeId, split.*
FROM #table AS t
CROSS APPLY
(
SELECT
StudentId = MAX(CASE split.RN WHEN 0 THEN split.String END),
SLocs = MAX(CASE split.RN WHEN 2 THEN split.String END),
SService = MAX(CASE split.RN WHEN 3 THEN split.String END),
SUnit = MAX(CASE split.RN WHEN 4 THEN split.String END),
SenZone = MAX(CASE split.RN WHEN 5 THEN split.String END),
SGeoloc = MAX(CASE split.RN WHEN 6 THEN split.String END),
SRegisted = MAX(CASE split.RN WHEN 7 THEN split.String END),
SGender = MAX(CASE split.RN WHEN 8 THEN split.String END),
SName = MAX(CASE split.RN WHEN 9 THEN split.String END)
FROM
(
SELECT RN = 0, String = SUBSTRING(t.String,1,CHARINDEX(',',t.String)-1)
UNION ALL
SELECT s.ItemNumber, clean.string
FROM (VALUES(t.string,CHARINDEX(',',t.String))) AS f(String,B)
CROSS APPLY dbo.DelimitedSplit8K(f.String,CHAR(10)) AS s
CROSS APPLY (VALUES(CHARINDEX('":',s.item))) AS d(Pos)
CROSS APPLY (VALUES(CHARINDEX(CHAR(13),s.item))) AS v(E)
CROSS APPLY (VALUES(REPLACE(SUBSTRING(
s.item,d.Pos+3,v.E-d.Pos-5),'"',''))) AS clean(String)
WHERE d.Pos > 0
) AS split
) AS split;
Returns:
SomeId StudentId SLocs SService SUnit SenZone SGeoloc SRegisted SGender SName
----------- ------------- ------------ --------------- ------ -------- -------- ---------- -------- ---------
1 1 US,Kric NY Volunteer Band1 UTC Ind FT Male Sam
2 1 US,Chicago Rock Star Band4 XFS Ill PT Female Juliana
One way to solve this, is to try to convert it to xml and parse that. something like the below:-
declare #d varchar(max)='1,{
"StudentLocs":["US","Kric"],
"Student_Service":["NY Volunteer"],
"Student_Unit":["Band1"],
"Student_enZone":["UTC"],
"Student_Geoloc":["Ind"],
"StudentRegisted":[FT"],
"StudentGender":["Male"],
"StudentName":["Sam"]
}'
Lets create a memory table to help in the convertion to xml, so we can make several replaces to original input.
Declare #replaceTable table(
id int identity(1,1),
item varchar(max), --item to find
[value] varchar(max) --item to replace with
)
insert into #replaceTable(item,[value]) values
(CHAR(13),''),(CHAR(10),''),
('StudentLocs:','</StudentId><StudentLocs>'),
('Student_Service:','</StudentLocs><Student_Service>'),
('Student_Unit:','</Student_Service><Student_Unit>'),
('Student_enZone:','</Student_Unit><Student_enZone>'),
('Student_Geoloc:','</Student_enZone><Student_Geoloc>'),
('StudentRegisted:','</Student_Geoloc><StudentRegisted>'),
('StudentGender:','</StudentRegisted><StudentGender>'),
('StudentName:','</StudentGender><StudentName>'),
('{',''),('}',''),('[',''),(']',''),('],',''),('"',''),(',{','')
declare #index int=(select COUNT(*) from #replaceTable)
set #d='<StudentId>'+#d+'</StudentName>' --some minor fix to the input
while(#index>0)--processing the replaces in desc order.
select #d=REPLACE(#d,item,[value]) ,#index=#index-1 from #replaceTable where id=#index
Declare #xml xml=#d
select
#xml.value('/StudentId[1]','int') StudentId,
#xml.value('/StudentLocs[1]','varchar(max)') SLocs ,
#xml.value('/Student_Service[1]','varchar(max)') SService ,
#xml.value('/Student_Unit[1]','varchar(max)') SUnit ,
#xml.value('/Student_enZone[1]','varchar(max)') SenZone ,
#xml.value('/Student_Geoloc[1]','varchar(max)') SGeoloc,
#xml.value('/StudentRegisted[1]','varchar(max)') SRegisted ,
#xml.value('/StudentGender[1]','varchar(max)') SGender ,
#xml.value('/StudentName[1]','varchar(max)') SName
The output will be as below:-
StudentId SLocs SService SUnit SenZone SGeoloc SRegisted SGender SName
1 US,Kric NY Volunteer Band1 UTC Ind FT Male Sam

Why is there a difference in my SQL output

This is puzzling me no end, and I know it might be tough without the data but thought it might be a longshot to post here.
Here goes, the first code I received was this
USE [Radiotherapy]
GO
if exists (
select * from tempdb.dbo.sysobjects o
where o.xtype in ('U')
and o.id = object_id(N'tempdb..#MySampleTemp')
)
DROP TABLE #MySampleTemp;
if exists (
select * from tempdb.dbo.sysobjects o
where o.xtype in ('U')
and o.id = object_id(N'tempdb..#MyPivotTemp')
)
DROP TABLE #MyPivotTemp;
SELECT [AttendanceNumber]
,CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END AS AgeRange
,[LocalPatientIdentifier]
,[ExaminationDate]
,[ExamExaminationCode] INTO #MySampleTemp
FROM [dbo].[tblRadiologyData]
WHERE AttendanceSiteCode IN('CNM','RNM')
--AND AttendanceStatus NOT IN ( 'Appt', 'Booked In', 'Cancelled', 'Pending' )
--AND AttendancePatientGroup = 'Out Patient'
--AND AttendancePatientCategory IN ( 'EU', 'Military', 'N.H.S.' )
--AND AttendanceSourceName <> 'PACs Support'
AND [ExaminationDate] >= '1 OCTOBER 2015' --
ORDER BY [AttendanceNumber], CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END, [LocalPatientIdentifier], [ExaminationDate], ExamExaminationCode
SELECT [AttendanceNumber],AgeRange,[LocalPatientIdentifier],[ExaminationDate], 1 AS ExamCount,
[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14] INTO #MyPivotTemp
FROM
(
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier]) rn
FROM #MySampleTemp
) AS st
pivot
(
MAX(ExamExaminationCode)
FOR rn in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14])
) AS pivottable
SELECT
[1] AS Exam01,
[2] AS Exam02,
[3] AS Exam03,
[4] AS Exam04,
[5] AS Exam05,
[6] AS Exam06,
[7] AS Exam07,
[8] AS Exam08,
[9] AS Exam09,
[10] AS Exam10,
[11] AS Exam11,
[12] AS Exam12,
[13] AS Exam13,
[14] AS Exam14,
COUNT(ExamCount) AS [No. Attendances]
FROM #MyPivotTemp
GROUP BY [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14]
ORDER BY [1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14]
What I tried to do was replicate this in query as follows:
USE [Radiotherapy]
;With CTE AS (SELECT s.attendanceNumber,
MAX(CASE WHEN s.rnk = 1 THEN s.ExamExaminationCode END) as examCode1,
MAX(CASE WHEN s.rnk = 2 THEN s.ExamExaminationCode END) as examCode2,
MAX(CASE WHEN s.rnk = 3 THEN s.ExamExaminationCode END) as examCode3,
MAX(CASE WHEN s.rnk = 4 THEN s.ExamExaminationCode END) as examCode4,
MAX(CASE WHEN s.rnk = 5 THEN s.ExamExaminationCode END) as examCode5,
MAX(CASE WHEN s.rnk = 6 THEN s.ExamExaminationCode END) as examCode6,
MAX(CASE WHEN s.rnk = 7 THEN s.ExamExaminationCode END) as examCode7,
MAX(CASE WHEN s.rnk = 8 THEN s.ExamExaminationCode END) as examCode8,
MAX(CASE WHEN s.rnk = 9 THEN s.ExamExaminationCode END) as examCode9,
MAX(CASE WHEN s.rnk = 10 THEN s.ExamExaminationCode END) as examCode10,
MAX(CASE WHEN s.rnk = 11 THEN s.ExamExaminationCode END) as examCode11,
MAX(CASE WHEN s.rnk = 12 THEN s.ExamExaminationCode END) as examCode12,
MAX(CASE WHEN s.rnk = 13 THEN s.ExamExaminationCode END) as examCode13,
MAX(CASE WHEN s.rnk = 14 THEN s.ExamExaminationCode END) as examCode14
FROM (
SELECT [AttendanceNumber]
,[ExaminationDate]
,[ExamExaminationCode]
,ROW_NUMBER() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [RadiologyID]) as rnk --Ordered by date ASC
FROM [Radiotherapy].[dbo].[tblRadiologyData] rd
where rd.ExaminationDate >= '01 october 2015'
and rd.AttendanceSiteCode IN('CNM','RNM') ) s
GROUP BY s.attendanceNumber)
Select CTE.examCode1,
CTE.examCode2,
CTE.examCode3,
CTE.examCode4,
CTE.examCode5,
CTE.examCode6,
CTE.examCode7,
CTE.examCode8,
CTE.examCode9,
CTE.examCode10,
CTE.examCode11,
CTE.examCode12,
CTE.examCode13,
CTE.examCode14,
COUNT(CTE.AttendanceNumber) as [No of occurances]
from CTE
GROUP by CTE.examCode1,
CTE.examCode2,
CTE.examCode3,
CTE.examCode4,
CTE.examCode5,
CTE.examCode6,
CTE.examCode7,
CTE.examCode8,
CTE.examCode9,
CTE.examCode10,
CTE.examCode11,
CTE.examCode12,
CTE.examCode13,
CTE.examCode14
ORDER BY CTE.examCode1
Great I thought until my code returned more results which puzzled me. Having broken it down I found the offending code from the original query:
ORDER BY [AttendanceNumber], CASE WHEN AgeAtExamDate BETWEEN 0 AND 5 THEN '0-5'
WHEN AgeAtExamDate BETWEEN 6 AND 18 THEN '6-18'
WHEN AgeAtExamDate BETWEEN 19 AND 150 THEN '19+'
ELSE 'Error' END, [LocalPatientIdentifier], [ExaminationDate], ExamExaminationCode
When I removed this from the first query the results matched, but my question is how and why is an ORDER BY affecting the output. I assumed this was just showing how the results are ordered? Understanding why code is doing what it's doing is something I really need to get my head around. Any advise more than welcome.
Probably it have something to do with this piece of code:
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier]) rn
FROM #MySampleTemp
Obviously your ordering is not breaking a tie(it isn't deterministic) and it produces rank number differently when you have ordered data in temp table and when not ordered. Try to add some PK to your temp table so the above code will look like:
SELECT *,
row_number() OVER(PARTITION BY [AttendanceNumber]
ORDER BY [AttendanceNumber], [LocalPatientIdentifier], [SomePK]) rn
FROM #MySampleTemp
Then removing ordering from first select statement will not have an effect on the result set.

How to get data on a single row

I have table called RUGS with the data below. How do I write a TSQl query to get the data as shown in Output. I am not familiar with unPIVOT
`cono ARtype days Revenue PPD
140 MCD 5 1000 500
140 MRA 6 2000 600
140 MRA 7 3000 700
141 MCD 1 5000 100
141 MRA 2 6000 200
141 MRA 3 7000 300`
Result
140 MCD 5 1000 500 MRA 6 2000 600 MRA 7 3000 700
141 MCD 1 5000 100 MRA 2 6000 200 MRA 3 7000 300
Given that every cono will have exactly 3 records (as stated in the comments), a cte with row_number can be used with case statements.
If any have less than three records, you will see blanks and zeroes in the results. Any with more than three will not have all records represented.
Here is an example with #RUGS as a table variable:
declare #RUGS table (cono int, ARType char(3), [days] int, Revenue int, PPD int)
insert into #RUGS VALUES
(140,'MCD',5,1000,500)
,(140,'MRA',6,2000,600)
,(140,'MRA',7,3000,700)
,(141,'MCD',1,5000,100)
,(141,'MRA',2,6000,200)
,(141,'MRA',3,7000,300);
with cte as
(
select row_number() over(partition by cono order by (select 1)) as rn, * from #RUGS
)
select cono,
max(case when rn = 1 then ARType else '' end) as ARType1,
max(case when rn = 1 then days else '' end) as days1,
max(case when rn = 1 then Revenue else '' end) as Revenue1,
max(case when rn = 1 then PPD else '' end) as PPD1,
max(case when rn = 2 then ARType else '' end) as ARType2,
max(case when rn = 2 then days else '' end) as days2,
max(case when rn = 2 then Revenue else '' end) as Revenue2,
max(case when rn = 2 then PPD else '' end) as PPD2,
max(case when rn = 3 then ARType else '' end) as ARType3,
max(case when rn = 3 then days else '' end) as days3,
max(case when rn = 3 then Revenue else '' end) as Revenue3,
max(case when rn = 3 then PPD else '' end) as PPD3
from cte group by cono

T-SQL CASE (SQL Server 2000)

I have a T-SQL query that I need to total out the counts for the CASE statements.
I tried to add a UNION but I am getting an error:
All queries in an SQL statement containing a UNION operator must have
an equal number of expressions in their target lists.
Any ideas? Thanks.
Query:
SELECT
CustomerID, Name, DueDate,
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 1
THEN PaymentAmount ELSE 0
END AS [Early],
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >=0
THEN PaymentAmount ELSE 0
END AS [On Time],
CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) = -1
THEN PaymentAmount ELSE 0
END AS [Late]
FROM
Customers
WHERE
DATEDIFF(MONTH, PaymentDate,DueDate), GetDate()) = 1
AND PaymentAmount= DuesAmount
UNION
SELECT
'-Total', '', CustomerID, Name, DueDate,
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 1
THEN PaymentAmount ELSE 0 END) AS [Early],
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) >= 0
THEN PaymentAmount ELSE 0 END) AS [On Time],
SUM(CASE WHEN DATEDIFF(Month, PaymentDate, DueDate) = -1
THEN PaymentAmount ELSE 0 END) AS [Late]
FROM
Customers
WHERE
DATEDIFF(MONTH, PaymentDate,DueDate), GetDate()) = 1
AND PaymentAmount = DuesAmount
The error says, "All queries in a SQL statement containing a UNION operator must have an equal number of expressions in their target lists." What this means is that each SELECT must return the same number of expressions.
In the code sample you gave us, the first SELECT statement returns 6 expressions, while the second one returns 8:
SELECT CustomerID, -- 1
Name, -- 2
DueDate, -- 3
CASE ... END AS [Early], -- 4
CASE ... END AS [On Time], -- 5
CASE ... END AS [Late] -- 6
...
UNION
SELECT '-Total', -- 1
'', -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
SUM(CASE ... END) AS [Early], -- 6
SUM(CASE ... END) AS [On Time], -- 7
SUM(CASE ... END) AS [Late] -- 8
...
See how the first SELECT returns 6 expressions, but the second returns 8? In a UNION, all the SELECT statements must return the same number of expressions.
You can return NULL in the first query for columns that don't have a match in the second, if necessary. For example:
SELECT NULL as [RowType], -- 1
NULL as [Padding], -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
CASE ... END AS [Early], -- 6
CASE ... END AS [On Time], -- 7
CASE ... END AS [Late] -- 8
...
UNION
SELECT '-Total', -- 1
'', -- 2
CustomerID, -- 3
Name, -- 4
DueDate, -- 5
SUM(CASE ... END) AS [Early], -- 6
SUM(CASE ... END) AS [On Time], -- 7
SUM(CASE ... END) AS [Late] -- 8
...
Also, note that you don't have a comma after the DueDate column.

Sum up items between setup of custom times

We need to count the number of items that occur 10 minutes before and 10 minutes after the hour, by day. We have a table that tracks the items individually. Ideally i would like to have the output be something like the below, but and totally open to other suggestions.
Table - Attendance
Att_item timestamp
1 2012-09-12 18:08:00
2 2012-09-01 23:26:00
3 2012-09-23 09:33:00
4 2012-09-11 09:43:00
5 2012-09-06 05:57:00
6 2012-09-17 19:26:00
7 2012-09-06 10:51:00
8 2012-09-19 09:42:00
9 2012-09-06 13:55:00
10 2012-09-05 07:26:00
11 2012-09-02 03:08:00
12 2012-09-19 12:17:00
13 2012-09-12 18:14:00
14 2012-09-12 18:14:00
Output
Date Timeslot_5pm Timeslot_6pm Timeslot_7pm
9/11/2012 11 22 22
9/12/2012 30 21 55
9/13/2012 44 33 44
Your requirements are not totally clear, but if you only want to count the number of records in the 20 minute window:
select cast(tstmp as date) date,
sum(case when datepart(hour, tstmp) = 1 then 1 else 0 end) Timeslot_1am,
sum(case when datepart(hour, tstmp) = 2 then 1 else 0 end) Timeslot_2am,
sum(case when datepart(hour, tstmp) = 3 then 1 else 0 end) Timeslot_3am,
sum(case when datepart(hour, tstmp) = 4 then 1 else 0 end) Timeslot_4am,
sum(case when datepart(hour, tstmp) = 5 then 1 else 0 end) Timeslot_5am,
sum(case when datepart(hour, tstmp) = 6 then 1 else 0 end) Timeslot_6am,
sum(case when datepart(hour, tstmp) = 7 then 1 else 0 end) Timeslot_7am,
sum(case when datepart(hour, tstmp) = 8 then 1 else 0 end) Timeslot_8am,
sum(case when datepart(hour, tstmp) = 9 then 1 else 0 end) Timeslot_9am,
sum(case when datepart(hour, tstmp) = 10 then 1 else 0 end) Timeslot_10am,
sum(case when datepart(hour, tstmp) = 11 then 1 else 0 end) Timeslot_11am,
sum(case when datepart(hour, tstmp) = 12 then 1 else 0 end) Timeslot_12pm,
sum(case when datepart(hour, tstmp) = 13 then 1 else 0 end) Timeslot_1pm,
sum(case when datepart(hour, tstmp) = 14 then 1 else 0 end) Timeslot_2pm,
sum(case when datepart(hour, tstmp) = 15 then 1 else 0 end) Timeslot_3pm,
sum(case when datepart(hour, tstmp) = 16 then 1 else 0 end) Timeslot_4pm,
sum(case when datepart(hour, tstmp) = 17 then 1 else 0 end) Timeslot_5pm,
sum(case when datepart(hour, tstmp) = 18 then 1 else 0 end) Timeslot_6pm,
sum(case when datepart(hour, tstmp) = 19 then 1 else 0 end) Timeslot_7pm,
sum(case when datepart(hour, tstmp) = 20 then 1 else 0 end) Timeslot_8pm,
sum(case when datepart(hour, tstmp) = 21 then 1 else 0 end) Timeslot_9pm,
sum(case when datepart(hour, tstmp) = 22 then 1 else 0 end) Timeslot_10pm,
sum(case when datepart(hour, tstmp) = 23 then 1 else 0 end) Timeslot_11pm
from yourtable
where datepart(minute, tstmp) >= 50
or datepart(minute, tstmp) <= 10
group by cast(tstmp as date)
If you want to count the number of records within each hour plus the records that are in the >=50 and <= 10 timeframe, then you will have to adjust this.
This does just one column (well 4 but you get my point).
select DATEPART(YYYY, FTSdate) as [year], DATEPART(mm, FTSdate) as [month]
, DATEPART(dd, FTSdate) as [day], DATEPART(hh, FTSdate) as [hour], COUNT(*)
from [Gabe2a].[dbo].[docSVsys]
where DATEPART(mi, FTSdate) >= 50 or DATEPART(mi, FTSdate) <= 10
group by DATEPART(YYYY, FTSdate), DATEPART(mm, FTSdate), DATEPART(dd, FTSdate), DATEPART(hh, FTSdate)
order by DATEPART(YYYY, FTSdate), DATEPART(mm, FTSdate), DATEPART(dd, FTSdate), DATEPART(hh, FTSdate)
Separate columns.
select DATEPART(YYYY, FTSdate) as [year], DATEPART(mm, FTSdate) as [month]
, DATEPART(dd, FTSdate) as [day]
, sum(case when DATEPART(hh, FTSdate) = '0' then 1 else 0 end) as [0:00] -- midnight
, sum(case when DATEPART(hh, FTSdate) = '1' then 1 else 0 end) as [1:00]
, sum(case when DATEPART(hh, FTSdate) = '2' then 1 else 0 end) as [2:00]
, sum(case when DATEPART(hh, FTSdate) = '3' then 1 else 0 end) as [3:00]
, sum(case when DATEPART(hh, FTSdate) = '4' then 1 else 0 end) as [4:00]
from [Gabe2a].[dbo].[docSVsys]
where DATEPART(mi, FTSdate) >= 50 or DATEPART(mi, FTSdate) <= 10
group by DATEPART(YYYY, FTSdate), DATEPART(mm, FTSdate), DATEPART(dd, FTSdate)
order by DATEPART(YYYY, FTSdate), DATEPART(mm, FTSdate), DATEPART(dd, FTSdate)