Find the difference between two fields in the same table - sql

I have a table which stores monthly billing information.
CREATE TABLE [dbo].[billing_history](
[id] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[reading_date] [date] NOT NULL,
[reading] [numeric](18, 0) NOT NULL,
[consumer_id] [int] NOT NULL)
The consumer_id is a foreign key referencing the consumer details table.
What i want is to subtract every customer current reading from the reading of the previous month. This would generate the current bill. Any ideas.

You could use something similar to this, where you would replace the values of the month/year that you want to return:
select b1.consumer_id,
sum(b1.reading - isnull(b2.reading, 0)) Total
from billing_history b1
left join billing_history b2
on b1.consumer_id = b2.consumer_id
and month(b2.reading_date) =12
and year(b2.reading_date) = 2012
where month(b1.reading_date) = 1
and year(b1.reading_date) = 2013
group by b1.consumer_id;
See SQL Fiddle with Demo.
If you don't want to pass in the values of the month and year to search and you only want the current/previous month, then you could use something similar to this using a CTE:
;with cur as
(
select consumer_id,
reading,
month(getdate()) curMonth,
year(getdate()) curYear,
case when month(getdate()) = 1 then 12 else month(getdate()) -1 end preMonth,
case when month(getdate()) = 1 then year(getdate())-1 else year(getdate()) end preYear
from billing_history
where month(reading_date) = month(getdate())
and year(reading_date) = year(getdate())
)
select c.consumer_id,
sum(c.reading - isnull(pre.reading, 0)) TotalReading
from cur c
left join billing_history pre
on c.consumer_id = pre.consumer_id
and month(pre.reading_date) = c.preMonth
and year(pre.reading_date) = c.preYear
group by c.consumer_id
See SQL Fiddle with Demo
This version gets both the current/previous month and year values to be used. If you are not familiar with CTE syntax, this can also be written as:
select c.consumer_id,
sum(c.reading - isnull(pre.reading, 0)) TotalReading
from
(
select consumer_id,
reading,
month(getdate()) curMonth,
year(getdate()) curYear,
case when month(getdate()) = 1 then 12 else month(getdate()) -1 end preMonth,
case when month(getdate()) = 1 then year(getdate())-1 else year(getdate()) end preYear
from billing_history
where month(reading_date) = month(getdate())
and year(reading_date) = year(getdate())
) c
left join billing_history pre
on c.consumer_id = pre.consumer_id
and month(pre.reading_date) = c.preMonth
and year(pre.reading_date) = c.preYear
group by c.consumer_id;
See SQL Fiddle with Demo.
As you can see in my queries I used the aggregate function SUM() and a GROUP BY on the consumer_id. I did this in the event you had more than one reading per customer. If you know you will only have one reading per month, then you could remove the aggregate.

Related

Move Functions from Where Clause to Select Statement

I have a union query that runs abysmally slow I believe mostly because there are two functions in the where clause of each union. I am pretty sure that there is no getting around the unions, but there may be a way to move the functions from the where of each. I won't post ALL of the union sections because I don't think it is necessary as they are all almost identical with the exception of one table in each. The first function was created by someone else but it takes a date, and uses the "frequency" value like "years, months, days, etc." and the "interval" value like 3, 4, 90 to calculate the new "Due Date". For instance, a date of today with a frequency of years, and an interval of 3, would produce the date 4/21/2025. Here is the actual function:
ALTER FUNCTION [dbo].[ReturnExpiration_IntervalxFreq](#Date datetime2,#int int, #freq int)
RETURNS datetime2
AS
BEGIN
declare #d datetime2;
SELECT #d = case when #int = 1 then null-- '12-31-9999'
when #int = 2 then dateadd(day,#freq,#date)
when #int = 3 then dateadd(week,#freq,#date)
when #int = 4 then dateadd(month,#freq,#date)
when #int = 5 then dateadd(quarter,#freq,#date)
when #int = 6 then dateadd(year,#freq,#date)
end
RETURN #d;
The query itself is supposed to find and identify records whose Due Date has past or is within 90 days of the current date. Here is what each section of the union looks like
SELECT
R.RequirementId
, EC.EmployeeCompanyId
, EC.CompanyId
, DaysOverdue =
CASE WHEN
R.DueDate IS NULL
THEN
CASE WHEN
EXISTS(SELECT 1 FROM tbl_Training_Requirement_Compliance RC WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId AND RC.RequirementId = R.RequirementId AND RC.Active = 1 AND ((DATEDIFF(DAY, R.DueDate, GETDATE()) > -91 OR R.DueDate Is Null ) OR (DATEDIFF(DAY, dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), GETDATE()) > -91)) OR R.IntervalId IS NULL)
THEN
DateDiff(day,ISNULL(dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), '12/31/9999'),getdate())
ELSE
0
END
ELSE
DATEDIFF(day,R.DueDate,getdate())
END
,CASE WHEN
EXISTS(SELECT 1 FROM tbl_Training_Requirement_Compliance RC WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId AND RC.RequirementId = R.RequirementId AND RC.Active=1 AND (GETDATE() > dbo.ReturnExpiration_IntervalxFreq(RC.EffectiveDate, R.IntervalId, R.Frequency) OR R.IntervalId IS NULL))
THEN
CONVERT(VARCHAR(12),dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), 101)
ELSE
CONVERT(VARCHAR(12),R.DueDate,101)
END As DateDue
FROM
#Employees AS EC
INNER JOIN dbo.tbl_Training_Requirement_To_Position TRP ON TRP.PositionId = EC.PositionId
INNER JOIN #CompanyReqs R ON R.RequirementId = TRP.RequirementId
LEFT OUTER JOIN tbl_Training_Requirement_Compliance TRC ON TRC.EmployeeCompanyId = EC.EmployeeCompanyId AND TRC.RequirementId = R.RequirementId AND TRC.Active = 1
WHERE
NOT EXISTS(SELECT 1
FROM tbl_Training_Requirement_Compliance RC
WHERE RC.EmployeeCompanyId = EC.EmployeeCompanyId
AND RC.RequirementId = R.RequirementId
AND RC.Active = 1
)
OR (
(DATEDIFF(DAY, R.DueDate, GETDATE()) > -91
OR R.DueDate Is Null )
OR (DATEDIFF(DAY, dbo.ReturnExpiration_IntervalxFreq(TRC.EffectiveDate, R.IntervalId, R.Frequency), GETDATE()) > -91))
UNION...
It is supposed to exclude records that either don't exist at all on the tbl_Training_Requirement_Compliance table, or if they do exist, once the frequency an intervals have been calculated, would have a new due date that is within 90 days of the current date. I am hoping that someone with much more experience and expertise in SQL Server can show me a way, if possible, to remove the functions from the WHERE clause and help the performance of this stored procedure.

Select Records against all months of a given year form one table with records from second table

I have two tables in my database:
MembershipInstallments (ProjectId, AllotmentId, InstallmentId, EntryDate, AmountPaid)
Memberships (ProjectId, AllotmentId, ClientId, ClientName, RegistrationNo)
I want to select month wise payments made by a clients in a year. And also amount paid before the start of that year. My desired result set is
Let's say for the year 2019:
ClientName, RegistrationNumbers, PreviouslyPaidAmount (i.e. all amounts paid in 2018), AmountPaidInJuly 2019, AmountPaidInAugust2019. ..... AmountPaidIn Jun2020
where month is EntryDate from MembershipInstallments table.
I tried it like this, but it takes too long for large data set:
SELECT
ClientName, RegistrationNo,
(SELECT ISNULL(SUM(AmountPaid),0)
FROM MembershipInstallments
WHERE ProjectId = Membership.ProjectId
AND AllotmentId = Membership.AllotmentId
AND EntryDate < #fromDate) ASPreviouslyPaid,
(SELECT ISNULL(SUM(AmountPaid), 0)
FROM MembershipInstallments
WHERE ProjectId = Membership.ProjectId
AND AllotmentId = Memberhsip.AllotmentId
AND (MONTH(EntryDate) = 7) AND (YEAR(EntryDate) = YEAR(#fromDate)) AS JulyPayment
FROM
Memberships
WHERE
ProjectId = #projectId
Any help will be highly appreciated.
Scalar Subqueries tend to be badly optimized. In your case (same join-conditions) you can simply utilize conditional aggregation:
SELECT ms.ClientName,ms.RegistrationNo,
Sum(CASE WHEN mi.EntryDate<#fromDate THEN mi.AmountPaid ELSE 0 end) AS PreviouslyPaid,
Sum(CASE WHEN (Month(mi.EntryDate) = 7) AND (Year(mi.EntryDate) = Year(#fromDate)) THEN mi.AmountPaid ELSE 0)
FROM Memberships AS ms
LEFT JOIN MembershipInstallments AS mi -- don't know if Outer join is really needed
ON mi.ProjectId=ms.ProjectId
AND mi.AllotmentId=ms.AllotmentId
WHERE ms.ProjectId=#projectId
You might be able to do the aggregation before the join, i.e. in a CTE to further improve performance:
WITH cte AS
(
SELECT
ProjectId, AllotmentId,
Sum(CASE WHEN EntryDate<#fromDate THEN AmountPaid ELSE 0 END) AS PreviouslyPaid,
Sum(CASE WHEN (Month(EntryDate) = 7) AND (Year(EntryDate) = Year(#fromDate)) THEN AmountPaid ELSE 0 END) AS JulyPayment
FROM MembershipInstallments
WHERE ProjectId=#projectId
GROUP BY ProjectId, AllotmentId
)
SELECT ms.ClientName, ms.RegistrationNo, cte.PreviouslyPaid, cte.JulyPayment
FROM Memberships AS ms
JOIN cte
ON cte.ProjectId=ms.ProjectId
AND cte.AllotmentId=ms.AllotmentId
WHERE ms.ProjectId=#projectId
In both cases double-check if the result is correct (depends on the actual relation between those tables)

Multiple Selects into one select

I'm trying to put some data together for a High Charts Bar chart using ASP.NET. Basically, i have three users who i need to track when they have logged into the system. the variants to be used are:
1) Today
2) This Week
3) Last Week
4) Last Month
So, i've created individual tsql scripts for today and and last week, but i'm now a little stuck on how to combine the two statemets, which will eventually be four.
SELECT Count(*) as CountToday from hitsTable WHERE Convert(date,hitDate) =
Convert(date,GETDATE()) Group by UserId
SELECT count(*) as CountLatWeek from hitTable
where hitDate between (DATEADD(week, DATEDIFF (week,0,GETDATE()),-1))
AND getDate() Group by UserId
Searhing on google, leads me to nested select statements, which all seem to form dependacies with the two statements. However, what i need to do is produce a table of results like this:
EDIT
I've set up a SQL Fiddle, so we can test out the examples
http://www.sqlfiddle.com/#!6/a21ec
the fiddle has tsql for today and tsql for last week (which may need some tweaking)
Select Distinct
UserId
, ( Select Count(*) as CountToday from hitsTable h2
Where h2.UserId = h1.UserId
And Convert(date,hitDate) = Convert(date,GETDATE())
) As CountToday
, ( Select count(*) as CountLatWeek from hitsTable h2
Where h2.UserId = h1.UserId
And hitDate Between DATEADD(dd, -(DATEPART(dw, GetDate())-1)-7, GetDate())
And DATEADD(dd, 7-(DATEPART(dw, GetDate()))-7, GetDate())
) As CountLastWeek
FROM hitsTable h1
Here’s another alternative based on #Avinash comment on the question.
Select
UserId
, CountTodayTable.CountToday
, CountLatWeekTable.CountLatWeek
, ...
FROM hitsTable h1
Inner Join
( Select Count(*) as CountToday from hitsTable h2
Where h2.UserId = h1.UserId
And Convert(date,hitDate) = Convert(date,GETDATE())
) CountTodayTable
On CountTodayTable.UserId = h1.UserId
Inner Join
( Select count(*) as CountLatWeek from hitTable h2
Where h2.UserId = h1.UserId
And hitDate between (DATEADD(week, DATEDIFF (week,0,GETDATE()),-1)) And getDate()
) CountLatWeekTable
On CountLatWeekTable.UserId = h1.UserId
...
Try this query
select
id,
sum(case when Convert(date,hitDate) = Convert(date,GETDATE()) then 1 else 0 end) as as CountToday,
sum(hitDate between (DATEADD(week, DATEDIFF (week,0,GETDATE()),-1)) AND getDate() then 1 else 0 end) as CountLatWeek,
...... -- Add more condition
from
hitsTable
group by
UserId
Edit
select
userid,
sum(case when Convert(date,hitDate) =
Convert(date,GETDATE()) then 1 else 0 end) as cnt
from
hitstable
group by userid
FIDDLE
| USERID | CNT |
|--------|-----|
| User1 | 3 |
| User2 | 0 |

SQL Left vs Right Outer Join. Return all values

PROBLEM: Need query to return the MONTH and YIELD for Each Year. For some reason, if the data is not found in a Month a.Month the query will not return the b.Month's Yield. I need the query to return all monthly data regardless of whether or not a.Month contains a month with data in the same months as "b".
THE FOLLOWING RESULT: SHOULD RETURN A VALUE FOR "MONTH 1 YIELD_1". But it doesn't... because "MONTH 1 YIELD_0" does NOT contain a value for month 1.
**DATA RESULTS WITH: LEFT OUTER JOIN:**
Month Yield_1 Yield_0
2 11.44 14
3 NULL 3.21
4 NULL 14.24
7 NULL 10.36
8 NULL 0
9 NULL -9.6
10 NULL 10.35
11 NULL 1.4
12 11.44 -1.18
**DATA RESULTS WITH RIGHT OUTER JOIN:**
Month Yield_1 Yield_0
NULL 11.44 NULL
2 11.44 14
12 11.44 -1.18
QUERY:
SET #ID_CARTERA = 8;
select
a.Month Month,
b.Monthly_Yield Yield_Year_1,
a.Monthly_Yield Yield_Year_0
from
( select
LEFT(A.F_ANOMES, 4) Year,
RIGHT(A.F_ANOMES, 2) Month,
ROUND(A.POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses A
where A.ID_CARTERA = #ID_CARTERA
And A.IND_RENTABILIDAD = 1
And LEFT(A.F_ANOMES, 4) = ( select MAX(left(F_ANOMES, 4 ) ) - 0 from dr_rent_carteras_meses where ID_CARTERA = #ID_CARTERA ) ) a
LEFT outer join
( select
LEFT(A.F_ANOMES, 4) Year,
RIGHT(A.F_ANOMES, 2) Month,
ROUND(A.POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses A
where A.ID_CARTERA = #ID_CARTERA
And A.IND_RENTABILIDAD = 1
And LEFT(A.F_ANOMES, 4) = ( select MAX(left(F_ANOMES, 4 ) ) - 1 from dr_rent_carteras_meses where ID_CARTERA = #ID_CARTERA ) ) b on ( a.Month = b.Month )
order by month asc
Summary
I don't think you need either left, right, or full join for this specific query as a GROUP BY/CASEbased solution should work just fine and be at least twice as much faster.
Problem Definition
I found this question rather interesting as it seems to arise from a real life situation and I believe that in real life FULL JOIN is seldom if ever necessary. So to me the real question is not how to combine the data from left and right joins but rather why is a full join needed in the first place?
Besides, simple replacing LEFT with FULL would not be enough as that would lead to
Duplicate rows for the same months;
NULL months for when the month is not available in the latest year.
So I decided to go ahead and decipher the query.
Table and Data Setup
Unfortunately, #smileyseven didn't provide table definitions or insert statements, so I had to work them out from the query and sample data. Based on the query syntax I'm assuming that SQL Server was used so that's what I use as well.
Here's my guess at how the table looks:
CREATE TABLE dr_rent_carteras_meses
(
F_ANOMES varchar(6) NOT NULL PRIMARY KEY,
POR_RENTABILIDAD float NOT NULL,
-- These columns are irrelevant
ID_CARTERA INT NOT NULL DEFAULT(8),
IND_RENTABILIDAD INT DEFAULT(1) NOT NULL
)
The important point ist hat F_ANOMES is probably the key column as otherwise we would have to expect multiple rows for each month in the query output and that seems unlikely.
The following insert statements should produce the sample data:
INSERT dr_rent_carteras_meses (F_ANOMES, POR_RENTABILIDAD) VALUES
('201202', 14),
('201203', 3.21),
('201204', 14.24),
('201207', 10.36),
('201208', 0),
('201209', -9.6),
('201210', 10.35),
('201211', 1.4),
('201212', -1.18),
('201101', 11.44),
('201102', 11.44),
('201112', 11.44)
Solution
The first thing to note is that we don't really need to calculate the maximum year two times, so we'll start with this:
declare #Max_Year int
select
#Max_Year = MAX(left(F_ANOMES, 4))
from dr_rent_carteras_meses
where ID_CARTERA = #ID_CARTERA
The a and b tables are virtually same, so we could probably reuse them:
;with
Monthly_Yield_CTE as
(
select
LEFT(F_ANOMES, 4) Year,
RIGHT(F_ANOMES, 2) Month,
ROUND(POR_RENTABILIDAD, 2) Monthly_Yield
from dr_rent_carteras_meses
where ID_CARTERA = #ID_CARTERA
and IND_RENTABILIDAD = 1
and LEFT(F_ANOMES, 4) in (#Max_Year, #Max_Year - 1)
)
and use the FULL JOIN but I think a better option is to simply group it by month:
select
[Month],
SUM(CASE WHEN [Year] = #Max_Year - 1 THEN Monthly_Yield ELSE 0 END) Yield_Year_1,
SUM(CASE WHEN [Year] = #Max_Year THEN Monthly_Yield ELSE 0 END) Yield_Year_0
from Monthly_Yield_CTE
group by [Month]
order by [Month]
One could use either the CTE version or re-write it without CTE as the query is simple enough:
SET #ID_CARTERA = 8
declare #Max_Year int
select
#Max_Year = MAX(left(F_ANOMES, 4))
from dr_rent_carteras_meses
where ID_CARTERA = #ID_CARTERA
select
RIGHT(F_ANOMES, 2) Month,
SUM(CASE
WHEN LEFT(F_ANOMES, 4) = #Max_Year - 1
THEN ROUND(POR_RENTABILIDAD, 2)
ELSE 0
END) Yield_Year_1,
SUM(CASE
WHEN LEFT(F_ANOMES, 4) = #Max_Year
THEN ROUND(POR_RENTABILIDAD, 2)
ELSE 0
END) Yield_Year_0
from dr_rent_carteras_meses
where ID_CARTERA = #ID_CARTERA
and IND_RENTABILIDAD = 1
and LEFT(F_ANOMES, 4) in (#Max_Year, #Max_Year - 1)
group by RIGHT(F_ANOMES, 2)
order by 1
The only drawback I'm aware of is that we get 0 instead of NULL for the months where the data is missing and I'm not sure if that's important.
Performance
The performance of this query seems to be quite a bit better; in my setup the relative combined cost of the GROUP BY/CASE query with a separated MAX is about 30% vs 70% for FULL JOIN solution.
Try FULL OUTER JOIN. See here:
http://en.wikipedia.org/wiki/Join_%28SQL%29#Full_outer_join

SQL Query in CRM Report

A "Case" in CRM has a field called "Status" with four options.
I'm trying to
build a report in CRM that fills a table with every week of the year (each row is a different week), and then counts the number of cases that have each Status option (the columns would be each of the Status options).
The table would look like this
Status 1 Status 2 Status 3
Week 1 3 55 4
Week 2 5 23 5
Week 3 14 11 33
So far I have the following:
SELECT
SUM(case WHEN status = 1 then 1 else 0 end) Status1,
SUM(case WHEN status = 2 then 1 else 0 end) Status2,
SUM(case WHEN status = 3 then 1 else 0 end) Status3,
SUM(case WHEN status = 4 then 1 else 0 end) Status4,
SUM(case WHEN status = 5 then 1 else 0 end) Status5
FROM [DB].[dbo].[Contact]
Which gives me the following:
Status 1 Status 2 Status 3
2 43 53
Now I need to somehow split this into 52 rows for the past year and filter these results by date (columns in the Contact table). I'm a bit new to SQL queries and CRM - any help here would be much appreciated.
Here is a SQLFiddle with my progress and sample data: http://sqlfiddle.com/#!2/85b19/1
Sounds like you want to group by a range. The trick is to create a new field that represents each range (for you one per year) and group by that.
Since it also seems like you want an infinite range of dates, marc_s has a good summary for how to do the group by trick with dates in a generic way: SQL group by frequency within a date range
So, let's break this down:
You want to make a report that shows, for each contact, a breakdown, week by week, of the number of cases registered to that contact, which is divided into three columns, one for each StateCode.
If this is the case, then you would need to have 52 date records (or so) for each contact. For calendar like requests, it's always good to have a separate calendar table that lets you query from it. Dan Guzman has a blog entry that creates a useful calendar table which I'll use in the query.
WITH WeekNumbers AS
(
SELECT
FirstDateOfWeek,
-- order by first date of week, grouping calendar year to produce week numbers
WeekNumber = row_number() OVER (PARTITION BY CalendarYear ORDER BY FirstDateOfWeek)
FROM
master.dbo.Calendar -- created from script
GROUP BY
FirstDateOfWeek,
CalendarYear
), Calendar AS
(
SELECT
WeekNumber =
(
SELECT
WeekNumber
FROM
WeekNumbers WN
WHERE
C.FirstDateOfWeek = WN.FirstDateOfWeek
),
*
FROM
master.dbo.Calendar C
WHERE
CalendarDate BETWEEN '1/1/2012' AND getutcdate()
)
SELECT
C.FullName,
----include the below if the data is necessary
--Cl.WeekNumber,
--Cl.CalendarYear,
--Cl.FirstDateOfWeek,
--Cl.LastDateOfWeek,
'Week: ' + CAST(Cl.WeekNumber AS VARCHAR(20))
+ ', Year: ' + CAST(Cl.CalendarYear AS VARCHAR(20)) WeekNumber
FROM
CRM.dbo.Contact C
-- use a cartesian join to produce a table list
CROSS JOIN
(
SELECT
DISTINCT WeekNumber,
CalendarYear,
FirstDateOfWeek,
LastDateOfWeek
FROM
Calendar
) Cl
ORDER BY
C.FullName,
Cl.WeekNumber
This is different from the solution Ben linked to because Marc's query only returns weeks where there is a matching value, whereas you may or may not want to see even the weeks where there is no activity.
Once you have your core tables of contacts split out week by week as in the above (or altered for your specific time period), you can simply add a subquery for each StateCode to see the breakdown in columns as in the final query below.
WITH WeekNumbers AS
(
SELECT
FirstDateOfWeek,
WeekNumber = row_number() OVER (PARTITION BY CalendarYear ORDER BY FirstDateOfWeek)
FROM
master.dbo.Calendar
GROUP BY
FirstDateOfWeek,
CalendarYear
), Calendar AS
(
SELECT
WeekNumber =
(
SELECT
WeekNumber
FROM
WeekNumbers WN
WHERE
C.FirstDateOfWeek = WN.FirstDateOfWeek
),
*
FROM
master.dbo.Calendar C
WHERE
CalendarDate BETWEEN '1/1/2012' AND getutcdate()
)
SELECT
C.FullName,
--Cl.WeekNumber,
--Cl.CalendarYear,
--Cl.FirstDateOfWeek,
--Cl.LastDateOfWeek,
'Week: ' + CAST(Cl.WeekNumber AS VARCHAR(20)) +', Year: ' + CAST(Cl.CalendarYear AS VARCHAR(20)) WeekNumber,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Active'
) ActiveCases,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Resolved'
) ResolvedCases,
(
SELECT
count(*)
FROM
CRM.dbo.Incident I
INNER JOIN CRM.dbo.StringMap SM ON
I.StateCode = SM.AttributeValue
INNER JOIN
(
SELECT
DISTINCT ME.Name,
ME.ObjectTypeCode
FROM
CRM.MetadataSchema.Entity ME
) E ON
SM.ObjectTypeCode = E.ObjectTypeCode
WHERE
I.ModifiedOn >= Cl.FirstDateOfWeek
AND I.ModifiedOn < dateadd(day, 1, Cl.LastDateOfWeek)
AND E.Name = 'incident'
AND SM.AttributeName = 'statecode'
AND SM.LangId = 1033
AND I.CustomerId = C.ContactId
AND SM.Value = 'Canceled'
) CancelledCases
FROM
CRM.dbo.Contact C
CROSS JOIN
(
SELECT
DISTINCT WeekNumber,
CalendarYear,
FirstDateOfWeek,
LastDateOfWeek
FROM
Calendar
) Cl
ORDER BY
C.FullName,
Cl.WeekNumber