SQL Server query with multiple select - sql

I have a query which select all car makes and count each make quantity in response
SELECT
q.Make, Count(q.ID)
FROM
(SELECT
cars.ID, cars.Make, cars.Model,
cars.Year1, cars.Month1, cars.KM, cars.VIN,
cars.Fuel, cars.EngineCap, cars.PowerKW,
cars.GearBox, cars.BodyType, cars.BodyColor,
cars.Doors, cars.FullName, Transport.address,
(DateDiff(second,Getdate(),cars.AuEnd)) as r,
cars.AuEnd, cars.BuyNowPrice, cars.CurrentPrice
FROM
cars
LEFT JOIN
Transport ON Cars.TransportFrom = Transport.ID
WHERE
Active = 'True'
AND AuEnd > GETDATE()
AND year1 >= 1900 AND year1 <= 2015
AND Make in ('AUDi', 'AIXAM', 'ALPINA')
ORDER BY
cars.make ASC, cars.model ASC
OFFSET 50 ROWS FETCH NEXT 50 ROWS ONLY) AS q
GROUP BY
q.make ORDER BY q.make ASC;
Now I need get in result as third field each make total count without offset,
so now I get result
Make CountInResponse
AIXAM 1
ALPINA 1
AUDI 48
But I need to get
Make CountInResponse Total
AIXAM 1 1
ALPINA 1 1
AUDI 48 100
I think I need something like
SELECT
q.Make, Count(q.ID),
(SELECT Make, Count(ID)
FROM cars
WHERE Active = 'True' AND AuEnd > GETDATE()
AND year1 >= 1900 AND year1 <= 2015
AND Make in ('AUDI', 'AIXAM', 'ALPINA')
GROUP BY Make) as q2
FROM
(SELECT
cars.ID, cars.Make, cars.Model,
cars.Year1, cars.Month1, cars.KM, cars.VIN,
cars.Fuel, cars.EngineCap, cars.PowerKW,
cars.GearBox, cars.BodyType, cars.BodyColor,
cars.Doors, cars.FullName, Transport.address,
(DateDiff(second,Getdate(),cars.AuEnd)) as r,
cars.AuEnd, cars.BuyNowPrice, cars.CurrentPrice
FROM
cars
LEFT JOIN
Transport ON Cars.TransportFrom = Transport.ID
WHERE
Active = 'True'
AND AuEnd > GETDATE()
AND year1 >= 1900 AND year1 <= 2015
AND Make in ('AUDi', 'AIXAM', 'ALPINA')
ORDER BY
cars.make ASC, cars.model ASC
OFFSET 50 ROWS FETCH NEXT 50 ROWS ONLY) AS q
But I get an error
Msg 116, Level 16, State 1, Line 10
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
How to write right syntax?

The problem is you are selecting two columns in q2 (ie) Make, Count(ID) you cannot do that in SQL Server.
Try something like this.
WITH cte AS
(
SELECT
row_number() OVER(order by cars.make ASC,cars.model ASC) AS rn,
cars.id, cars.make
FROM
cars
LEFT JOIN
transport ON cars.transportfrom = transport.id
WHERE
active = 'True'
AND auend > getdate()
AND year1 >= 1900 AND year1 <= 2015
AND make IN ('AUDI', 'AIXAM', 'ALPINA')
)
SELECT
make ,
count(CASE WHEN RN BETWEEN 50 AND 100 THEN 1 END) AS countinresponse,
count(1) AS total
FROM
cte
GROUP BY
make
Or you need to convert the sub-query in select to correlated sub-query
SELECT q.make,
Count(q.id) countinresponse,
(
SELECT Count(id)
FROM cars C1
WHERE c1.id = q.id
AND active='True'
AND auend > Getdate()
AND year1 >= 1900
AND year1 <= 2015
AND make IN ('AUDi',
'AIXAM',
'ALPINA')
GROUP BY make) AS total
FROM (
SELECT cars.id,
cars.make
FROM cars
LEFT JOIN transport
ON cars.transportfrom=transport.id
WHERE active='True'
AND auend > Getdate()
AND year1 >= 1900
AND year1 <= 2015
AND make IN ('AUDi',
'AIXAM',
'ALPINA')
ORDER BY cars.make ASC,
cars.model ASC offset 50 rowsfetch next 50 rows only ) AS q
GROUP BY q.make
ORDER BY q.make ASC;

Related

List count for last 12 months broken down by month

I have a query that can get a total active count of products until a specified date #POINT
SELECT
COUNT(DISTINCT e.productId) CNT
FROM
pro p
OUTER APPLY (
SELECT
TOP 1 p2.*
FROM
pro p2
WHERE
p2.productId = p.productId
AND p2.date >= #POINT
AND p2.STATUS IN ('SOLD', 'ACTIVE')
ORDER BY
p2.date ASC
) NEXT
WHERE
p.date < #POINT
AND p.STATUS = 'SOLD'
AND NEXT.productId IS NOT NULL
Output for #POINT "01/01/2021" is
CNT
500
From a table like
productId date STATUS
1001 01/04/2021 ACTIVE
1002 01/06/2021 SOLD
1003 01/07/2021 OTHER
...
How would I remake this query so that I can have a list of points (last 12 months) like
POINT CNT
02/01/2021 550
01/01/2021 500
12/01/2020 450
...
03/01/2020 550
in one query? I don't want to create a separate table of dates. The database is MSSQL.
Since no responded to question, I'll assume there isn't a function to generate these dates efficiently. I wrote a subquery that CAST couple dates to varchar to date, resulting with first months for the past 12 months.
Just group it by the Point and COUNT(*) the result.
You say in your update "CAST couple dates to varchar to date", which I think means you want just the date part, in which case you can use CAST(NEXT.date AS date):
SELECT
NEXT.date POINT, -- or CAST(NEXT.date AS date)
COUNT(*) CNT
FROM
pro p
OUTER APPLY (
SELECT
TOP 1 p2.*
FROM
pro p2
WHERE
p2.productId = p.productId
AND p2.date >= #POINT
AND p2.STATUS IN ('SOLD', 'ACTIVE')
ORDER BY
p2.date ASC
) NEXT
WHERE
p.date < #POINT
AND p.STATUS = 'SOLD'
AND NEXT.productId IS NOT NULL
GROUP BY
NEXT.date; -- or CAST(NEXT.date AS date)

Need all Sales Reps on one Line

Below I have the following SQL Statement:
WITH SalesDetail as (
SELECT
PostAR.TxDate
,PostAR.AccountLink
,PostST.AccountLink AS StkLnk
,PostST.Quantity AS QtySold
,PostST.cAuditNumber
,(PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost) AS Profit
,(((PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost)))/((((PostST.Credit-PostST.Debit))))*100 AS GrossProfitPercent
,(PostST.Quantity*PostST.Cost) AS Cost
,(PostST.Credit-PostST.Debit) AS TotSales
,(((PostST.Credit-PostST.Debit)-(PostST.Quantity*PostST.Cost))) / ((((PostST.Quantity*PostST.Cost)+(0.00000000000001))))*100 AS MarkUpPercent
,concat(StkItem.Code, ' - ' ,StkItem.Description_1) AS StkItemCode
,SalesRep.Code AS RepCode
,SalesRep.Name AS RepName
,Client.Account CustID
,Client.Name AS CustName
,CASE
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) > 0 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 25 THEN 2
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 25 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 35 THEN 2.5
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 35 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 45 THEN 3
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 45 AND ((((PostST.Credit+PostST.Debit)-((PostST.Cost+0.0000001)*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) < 55 THEN 3.5
WHEN ((((PostST.Credit+PostST.Debit)-(PostST.Cost*PostST.Quantity))/((PostST.Cost+0.0000001)*PostST.Quantity))*100) >= 55 THEN 4
ELSE 0
END AS CommPayablePercent
FROM PostAR
INNER JOIN PostST
ON PostST.cAuditNumber = PostAR.cAuditNumber
INNER JOIN StkItem
ON StkItem.StockLink = PostST.AccountLink
INNER JOIN SalesRep
ON SalesRep.idSalesRep = PostAR.RepID
INNER JOIN Client
ON Client.DCLink = PostAR.AccountLink
)
SELECT SalesDetail.RepName
, (((SalesDetail.CommPayablePercent)/100)) * ((SalesDetail.TotSales)) As RepTotComm
, SUM(SalesDetail.TotSales) AS TotalSales
FROM SalesDetail
GROUP BY SalesDetail.RepName, SalesDetail.TotSales, SalesDetail.CommPayablePercent
ORDER BY SalesDetail.RepName
I then get the following result:
As you can see, it is multipling the TotSales by my already determained CASE formulala. That is fine. However, I do not want the reps all on a each line. I want just the rep name and then the total commission payable.
Eg:
GRAY MEIRING - $5000 - $6000
and not:
GRAY MEIRING
GRAY MEIRING
GRAY MEIRING etc etc...
Is the issue coming from my SUM function or perhaps my GROUP BY function?
Many thanks! :)
You should use GROUP BY SalesDetail.RepName only, to achieve It, you can add subquery, try something like that:
................
SELECT RepName,
SUM(RepTotComm),
SUM(TotalSales)
FROM (
SELECT SalesDetail.RepName
, (((SalesDetail.CommPayablePercent)/100)) * ((SalesDetail.TotSales)) As RepTotComm
, SUM(SalesDetail.TotSales) AS TotalSales
FROM SalesDetail
GROUP BY SalesDetail.RepName, SalesDetail.TotSales, SalesDetail.CommPayablePercent
) x
GROUP BY RepName
ORDER BY RepName

SQL Deduct value from multiple rows

I would like to apply total $10.00 discount for each customers.The discount should be applied to multiple transactions until all $10.00 used.
Example:
CustomerID Transaction Amount Discount TransactionID
1 $8.00 $8.00 1
1 $6.00 $2.00 2
1 $5.00 $0.00 3
1 $1.00 $0.00 4
2 $5.00 $5.00 5
2 $2.00 $2.00 6
2 $2.00 $2.00 7
3 $45.00 $10.00 8
3 $6.00 $0.00 9
The query below keeps track of the running sum and calculates the discount depending on whether the running sum is greater than or less than the discount amount.
select
customerid, transaction_amount, transactionid,
(case when 10 > (sum_amount - transaction_amount)
then (case when transaction_amount >= 10 - (sum_amount - transaction_amount)
then 10 - (sum_amount - transaction_amount)
else transaction_amount end)
else 0 end) discount
from (
select customerid, transaction_amount, transactionid,
sum(transaction_amount) over (partition by customerid order by transactionid) sum_amount
from Table1
) t1 order by customerid, transactionid
http://sqlfiddle.com/#!6/552c2/7
same query with a self join which should work on most db's including mssql 2008
select
customerid, transaction_amount, transactionid,
(case when 10 > (sum_amount - transaction_amount)
then (case when transaction_amount >= 10 - (sum_amount - transaction_amount)
then 10 - (sum_amount - transaction_amount)
else transaction_amount end)
else 0 end) discount
from (
select t1.customerid, t1.transaction_amount, t1.transactionid,
sum(t2.transaction_amount) sum_amount
from Table1 t1
join Table1 t2 on t1.customerid = t2.customerid
and t1.transactionid >= t2.transactionid
group by t1.customerid, t1.transaction_amount, t1.transactionid
) t1 order by customerid, transactionid
http://sqlfiddle.com/#!3/552c2/2
You can do this with recursive common table expressions, although it isn't particularly pretty. SQL Server stuggles to optimize these types of query. See Sum of minutes between multiple date ranges for some discussion.
If you wanted to go further with this approach, you'd probably need to make a temporary table of x, so you can index it on (customerid, rn)
;with x as (
select
tx.*,
row_number() over (
partition by customerid
order by transaction_amount desc, transactionid
) rn
from
tx
), y as (
select
x.transactionid,
x.customerid,
x.transaction_amount,
case
when 10 >= x.transaction_amount then x.transaction_amount
else 10
end as discount,
case
when 10 >= x.transaction_amount then 10 - x.transaction_amount
else 0
end as remainder,
x.rn as rn
from
x
where
rn = 1
union all
select
x.transactionid,
x.customerid,
x.transaction_amount,
case
when y.remainder >= x.transaction_amount then x.transaction_amount
else y.remainder
end,
case
when y.remainder >= x.transaction_amount then y.remainder - x.transaction_amount
else 0
end,
x.rn
from
y
inner join
x
on y.rn = x.rn - 1 and y.customerid = x.customerid
where
y.remainder > 0
)
update
tx
set
discount = y.discount
from
tx
inner join
y
on tx.transactionid = y.transactionid;
Example SQLFiddle
I usually like to setup a test environment for such questions. I will use a local temporary table. Please note, I made the data un-ordered since it is not guaranteed in a real life.
-- play table
if exists (select 1 from tempdb.sys.tables where name like '%transactions%')
drop table #transactions
go
-- play table
create table #transactions
(
trans_id int identity(1,1) primary key,
customer_id int,
trans_amt smallmoney
)
go
-- add data
insert into #transactions
values
(1,$8.00),
(2,$5.00),
(3,$45.00),
(1,$6.00),
(2,$2.00),
(1,$5.00),
(2,$2.00),
(1,$1.00),
(3,$6.00);
go
I am going to give you two answers.
First, in 2014 there are new windows functions for rows preceding. This allows us to get a running total (rt) and a rt adjusted by one entry. Give these two values, we can determine if the maximum discount has been exceeded or not.
-- Two running totals for 2014
;
with cte_running_total
as
(
select
*,
SUM(trans_amt)
OVER (PARTITION BY customer_id
ORDER BY trans_id
ROWS BETWEEN UNBOUNDED PRECEDING AND
0 PRECEDING) as running_tot_p0,
SUM(trans_amt)
OVER (PARTITION BY customer_id
ORDER BY trans_id
ROWS BETWEEN UNBOUNDED PRECEDING AND
1 PRECEDING) as running_tot_p1
from
#transactions
)
select
*
,
case
when coalesce(running_tot_p1, 0) <= 10 and running_tot_p0 <= 10 then
trans_amt
when coalesce(running_tot_p1, 0) <= 10 and running_tot_p0 > 10 then
10 - coalesce(running_tot_p1, 0)
else 0
end as discount_amt
from cte_running_total;
Again, the above version is using a common table expression and advanced windowing to get the totals.
Do not fret! The same can be done all the way down to SQL 2000.
Second solution, I am just going to use the order by, sub-queries, and a temporary table to store the information that is normally in the CTE. You can switch the temporary table for a CTE in SQL 2008 if you want.
-- w/o any fancy functions - save to temp table
select *,
(
select count(*) from #transactions i
where i.customer_id = o.customer_id
and i.trans_id <= o.trans_id
) as sys_rn,
(
select sum(trans_amt) from #transactions i
where i.customer_id = o.customer_id
and i.trans_id <= o.trans_id
) as sys_tot_p0,
(
select sum(trans_amt) from #transactions i
where i.customer_id = o.customer_id
and i.trans_id < o.trans_id
) as sys_tot_p1
into #results
from #transactions o
order by customer_id, trans_id
go
-- report off temp table
select
trans_id,
customer_id,
trans_amt,
case
when coalesce(sys_tot_p1, 0) <= 10 and sys_tot_p0 <= 10 then
trans_amt
when coalesce(sys_tot_p1, 0) <= 10 and sys_tot_p0 > 10 then
10 - coalesce(sys_tot_p1, 0)
else 0
end as discount_amt
from #results
order by customer_id, trans_id
go
In short, your answer is show in the following screen shot. Cut and paste the code into SSMS and have some fun.

Calculate the qty of items that were purchased more than once by a customer - but need to exclude the first order qty

SELECT TOP 100 PERCENT soheader.custid,SOHeader.OrdNbr, SOLine.InvtID, SOLine.Descr,SOLine.QtyOrd
FROM SOHeader INNER JOIN
SOLine ON SOHeader.OrdNbr = SOLine.OrdNbr
WHERE (SOHeader.OrdDate >= CONVERT(DATETIME, '2013-06-01 00:00:00', 102)) AND (SOHeader.OrdDate <= GETDATE()) AND (SOHeader.CustID = '69065')
ORDER BY SOLine.InvtID, SOHeader.OrdNbr
here is my sample data
69065 WO0175279 69407 Jazzy Laces White 3
69065 WO0175393 69407 Jazzy Laces White 6
69065 WO0175393 69407 Jazzy Laces White 9
Now I want to know how to get the total qty of this item ordered after the first order. I do not want to include the qty of 3 in the first record above. I just want to include the qty of 6 in the first reorder and the qty 9 of the second reorder which equals the qty of 15.
69065 is the customer ID
WO##### is the order ID
69407 is the inventory ID
SELECT invtId, SUM(QtyOrd)
FROM (
SELECT invtId,
qtyOrd,
ROW_NUMBER() OVER (PARTITION BY invtId ORDER BY h.ordDate, h.ordNbr) rn
FROM soLine l
JOIN soHeader h
ON h.ordNbr = l.ordNbr
WHERE l.custId = 69065
) q
WHERE rn > 1
GROUP BY
invtId
WITH cl
as
(select *, ROW_NUMBER() OVER (PARTITION BY InvtID ORDER BY QtyOrd) rn
from t)
select InvtID, QtyOrd,
(select SUM(QtyOrd) from cl oo
where o.InvtID = oo.InvtID and o.rn -1 > 0
and rn between o.rn -1 and o.rn) as 'sm'
from cl o
Here's a Demo on SqlFiddle.

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