How to take out values from 2 different CTE results - sql

I have 2 result sets from different CTE selects, and i need to take out the value of 2 columns in first table from the value of 2 columns in second table.
Query description: In first result i find count of total new customers, and in the second result i get the customers that have any sales ( joining the factsales table ) and what i need is to find the count of new customers that dont have any invoices ( revenue made ). So from my logic that will mean the total number of customers from the first result - the total number of customers that have any revenue ( meaning they can be found in the factSales table ). So the count of customers without any revenue are found in customer table, but arent in factsales table. I hope this simplifies my issue and expectations. Thanks for the help provided.
use dwh01;
-- Total number of new customers
with cte1 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM [dwh01].[live].[DimCustomer] c
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
)
select
c.[Year],
c.[month],
count(distinct c.New_Customers_Per_Month_1080) as New_Customers_1080,
count(distinct c.New_Customers_Per_Month_1081) as New_Customers_1081
from cte1 c
group by c.[Year], c.[month]
order by c.[year] asc, c.[month] asc
;
-- new customers that have any revenue
with cte1 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM live.FactSales fs
inner join [live].[DimCustomer] c
on fs.customerkey = c.CustomerKey
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
)
select
c.[Year],
c.[month],
count(distinct c.New_Customers_Per_Month_1080) as New_Customers_1080,
count(distinct c.New_Customers_Per_Month_1081) as New_Customers_1081
from cte1 c
group by c.[Year], c.[month]
order by c.[year] asc, c.[month] asc
Result from first table:
Expected result:

You can define any number of common table expression sequentially. Here I have created two cte named cte1 and cte2 first then joined both with [year] and [month] column and used group by clause to get what you want.
with cte1 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM [dwh01].[live].[DimCustomer] c
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
) , cte2 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM live.FactSales fs
inner join [live].[DimCustomer] c
on fs.customerkey <> c.CustomerKey
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
)
select
c.[Year],
c.[month],
(count(distinct c.New_Customers_Per_Month_1080)-count(distinct c2.New_Customers_Per_Month_1080)) as New_Customers_1080,
(count(distinct c.New_Customers_Per_Month_1081)-count(distinct c2.New_Customers_Per_Month_1081)) as New_Customers_1081
from cte1 c inner join cte2 c2
on c.[year]=c2.[year] and c.[month]=c2.[month]
group by c.[Year], c.[month]
order by c.[year] asc, c.[month] asc

You can have two CTEs defined first and later you can join them, as given below:
-- Total number of new customers
;with cte1 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM [dwh01].[live].[DimCustomer] c
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
) , cte2 as(
SELECT
d.[Year],
d.[month],
case when c.branchid = '1080' then c.customerid end as New_Customers_Per_Month_1080,
case when c.branchid = '1081' then c.customerid end as New_Customers_Per_Month_1081
FROM live.FactSales fs
inner join [live].[DimCustomer] c
on fs.customerkey <> c.CustomerKey
inner join live.DimDate d -- Date join
on d.DayDate = c.Createdate
where d.DayDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-12, 0) and d.DayDate <= DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1) and c.IsActive = 'Y'
)
SELECT cte1.Year
, cte1.Month
, (cte1.New_Customers_Per_Month_1080 - cte2.New_Customers_Per_Month_1080) AS New_Customers_1080
,, (cte1.New_Customers_Per_Month_1081 - cte2.New_Customers_Per_Month_1081) AS New_Customers_1081
FROM cte1
INNER JOIN cte2
ON cte2.Year = cte1.Year AND cte2.Month = cte1.Month

Related

Group by customer and calculate sum in SQL and return the top 15

I want Group by customer and sum CuryDocBal and return the top 15 customers after grouping
My current code only returns 15 rows. For example, I want Morton Salt Company's totals to be summed and represent 1 row.
select top 15 a.Name ,d.CuryDocBal
from
ARDoc d
inner join
[AR_Balances] b
on d.CpnyID = b.CpnyID
inner join [SIVSYS].[dbo].[Company] c
on b.CpnyID = c.CpnyID
inner join Customer a
on d.CustId = a.Custid
--DocType = 'IN'
where
d.dueDate BETWEEN dateadd(day, -21, cast(getdate() as date)) and dateadd(day, 7, cast(getdate() as date))
and CuryDocBal <> 0
group by a.Name ,
d.CuryDocBal
order by d.CuryDocBal desc;
you need sum()
select top 15 a.Name, d.DueDate, sum(d.CuryDocBal) curyDocBal ,d.RefNbr, d.BatNbr,
b.CpnyID
,c.CpnyName
from
ARDoc d
inner join
[AR_Balances] b
on d.CpnyID = b.CpnyID
inner join [SIVSYS].[dbo].[Company] c
on b.CpnyID = c.CpnyID
inner join Customer a
on d.CustId = a.Custid
--DocType = 'IN'
where
d.dueDate BETWEEN dateadd(day, -21, cast(getdate() as date)) and dateadd(day, 7, cast(getdate() as date))
-- and d.dueDate < dateadd(day, 7, cast(getdate() as date))
-- (DueDate BETWEEN GETDATE() AND DATEADD(DAY, +7, GETDATE())
--or
--DueDate BETWEEN DATEADD(day,-21, GETDATE()) AND GETDATE())
and CuryDocBal <> 0
group by a.Name, d.DueDate,
d.CuryDocBal, b.CpnyID
,c.CpnyName, d.RefNbr, d.BatNbr
order by d.CuryDocBal desc;
Remove CuryDocBal from the group by and sum it instead.
select top 15
a.Name,
TotalCuryDocBal = sum(d.CuryDocBal)
from ARDoc d
inner join [AR_Balances] b on d.CpnyID = b.CpnyID
inner join [SIVSYS].[dbo].[Company] c on b.CpnyID = c.CpnyID
inner join Customer a on d.CustId = a.Custid
--DocType = 'IN'
where
d.dueDate BETWEEN dateadd(day, -21, cast(getdate() as date)) and dateadd(day, 7, cast(getdate() as date))
and CuryDocBal <> 0
group by a.Name
order by TotalCuryDocBal desc;

0 Results Effecting Entire Query

I was wondering if there is a way to make a results from a JOIN of a subquery result a predefined entry.
The query below pulls in the MAX(ReceiveDate) for the uniqueID JobNo. However, if nothing has been received the entire result will not show up. There are several other joins that could have data.
--***SUB QUERY (Receiver)
JOIN
(
SELECT
MAX(cast(r.ReceiveDate as DATE)) as ReceiveDate,
por.JobNo
FROM
POReleases as por
INNER JOIN
Receiver as r on por.PONum = r.PONum
GROUP BY por.JobNo
) r
ON r.JobNo = o.JobNo
The query will ultimately pull in data from purchase orders, result the most recent date, and the receiver with its most recent date based on the JobNo.
If nothing is received then result 'Whatever' or NULL. Anything.
The entire query is below:
DECLARE #now DATETIME
DECLARE #90daysago DATETIME
SET #now = GETDATE()
SET #90daysago = DATEADD(day, -90, #now)
;with cte as
(
SELECT
o.PartNo,
o.JobNo,
ord.DateEnt as oDateEnt,
por.MAXPONum,
po.DateEnt as poDateEnt,
tt.MAXtt,
r.ReceiveDate,
CASE
WHEN po.DateEnt >= r.ReceiveDate AND po.DateEnt >= tt.MAXtt THEN cast(po.DateEnt as DATE)
WHEN r.ReceiveDate >= po.DateEnt AND r.ReceiveDate >= tt.MAXtt THEN cast(r.ReceiveDate as DATE)
WHEN tt.MAXtt >= po.DateEnt AND tt.MAXtt >= r.ReceiveDate THEN cast(tt.MAXtt as DATE)
ELSE po.DateEnt
END AS MostRecentDate,
POProrate.TotalCost,
WIPProrate.WIPProrateCost,
(POProrate.TotalCost+WIPProrate.WIPProrateCost) as ProratedCost,
(ROUND(cast((o.QtyToMake - o.QtyShipped2Stock) as FLOAT)/o.QtyToMake,3))*(POProrate.TotalCost+WIPProrate.WIPProrateCost) as TotalProratedCost,
ROW_NUMBER() OVER(PARTITION BY o.JobNo ORDER BY tt.MAXtt DESC) as RowNum
FROM
--***MAIN QUERY (OrderDet)***
OrderDet as o
--***SUB QUERY (Order)***
JOIN
(
SELECT
cast(DateEnt as DATE) as DateEnt,
OrderNo
FROM
Orders
) ord
ON ord.OrderNo = o.OrderNo
--***SUB QUERY (POReleases)***
JOIN
(
SELECT
MAX(PONum) as MAXPONum,
JobNo
FROM
POReleases
GROUP BY
JobNo
) por
ON por.JobNo = o.JobNo
--***SUB QUERY (PO)***
JOIN
(
SELECT
PONum,
cast(DateEnt as DATE) as DateEnt
FROM
PO
) po
ON po.PONum = por.MAXPONum
--***SUB QUERY (TimeTicketDet)
JOIN
(
SELECT MAX(CAST(TicketDate as DATE)) as MaxTT,
JobNo
FROM TimeTicketDet as tt
GROUP BY JobNo
) tt
ON tt.JobNo = o.JobNo
--***SUB QUERY (Receiver)
JOIN
(
SELECT
MAX(cast(r.ReceiveDate as DATE)) as ReceiveDate,
por.JobNo
FROM
POReleases as por
INNER JOIN
Receiver as r on por.PONum = r.PONum
GROUP BY por.JobNo
) r
ON r.JobNo = o.JobNo
--***SUB QUERY (POProrate)***
JOIN
(
SELECT
j.JobNo,
SUM(j.TotalCost) as TotalCost
FROM
(
SELECT
por.JobNo,
CASE
WHEN pod.Unit = 'LOT' THEN SUM(pod.UnitCost*1)
ELSE SUM(por.Qty*pod.UnitCost)
END as TotalCost
FROM
PODet as pod
INNER JOIN
POReleases as por ON pod.PONum = por.PONum and pod.partno=por.partno
GROUP BY por.JobNo, pod.Unit
) j
GROUP BY j.JobNo
) POProrate
ON o.JobNo = POProrate.JobNo
--***SUB QUERY (WIPProrate)***
JOIN
(
SELECT
j.JobNo,
SUM(j.ProratedCost) as WIPProrateCost
FROM
(
SELECT
tt.StepNo,
tt.JobNo,
tt.ActualPayRate,
tt.BurdenRate,
tt.CycleTime,
tt.SetupTime,
tt.CycleTime + tt.SetupTime as TotalTime,
(tt.CycleTime + tt.SetupTime) * tt.ActualPayRate as LaborCost,
(tt.CycleTime + tt.SetupTime) * tt.BurdenRate as BurdenCost,
((tt.CycleTime + tt.SetupTime) * tt.ActualPayRate) + ((tt.CycleTime + tt.SetupTime) * tt.BurdenRate) as ProratedCost
FROM
TimeTicketDet as tt
) j
GROUP BY j.JobNo
) WIPProrate
ON WIPProrate.JobNo = o.JobNo
WHERE
o.Status = 'Open'
AND o.JobNo <> ''
AND ord.DateEnt <= #90daysago
AND po.DateEnt <= #90daysago
AND tt.MAXtt <= #90daysago
AND r.ReceiveDate <= #90daysago
)
SELECT *
FROM cte
WHERE
RowNum = 1
Your sub query needs to be a LEFT JOIN instead of a regular JOIN which will allow it to include results if present and NULL otherwise.
--***SUB QUERY (Receiver)
LEFT JOIN
(
SELECT
MAX(cast(r.ReceiveDate as DATE)) as ReceiveDate,
por.JobNo
FROM
POReleases as por
INNER JOIN
Receiver as r on por.PONum = r.PONum
GROUP BY por.JobNo
) r
ON r.JobNo = o.JobNo

Count Number of games per product type

How can I count NumOfGames% per product type like % = TOTAL/PERPRODUT_TYPE.
Here is my query for the TOTAL NumOfGames
SELECT
DPT.[Name] [ProductType],
SUM([FinishedGameCycleCount]) [NumOfGames]
FROM [WarehouseMgmt].[FactGameAgr] FWA
JOIN [WarehouseMgmt].[DimPlayer] DPL ON FWA.[PlayerId] = DPL.[Id]
JOIN [WarehouseMgmt].[DimGame] DG ON FWA.[GameId] = DG.[Id]
JOIN [WarehouseMgmt].[DimProductType] DPT ON DPT.Id = FWA.ProductTypeId
WHERE [WarehouseMgmt].[GetDateTimeFromTimeId](TimeId) >= Dateadd(Month, Datediff(Month, 0, DATEADD(m, -6, current_timestamp)), 0)
GROUP BY DPT.[Name]
Use SUM() OVER()
SELECT
DPT.[Name] [ProductType],
SUM([FinishedGameCycleCount]) [NumOfGames],
SUM([FinishedGameCycleCount]) *100. / SUM(SUM([FinishedGameCycleCount])) OVER() [percentage]
FROM [WarehouseMgmt].[FactGameAgr] FWA
JOIN [WarehouseMgmt].[DimPlayer] DPL ON FWA.[PlayerId] = DPL.[Id]
JOIN [WarehouseMgmt].[DimGame] DG ON FWA.[GameId] = DG.[Id]
JOIN [WarehouseMgmt].[DimProductType] DPT ON DPT.Id = FWA.ProductTypeId
WHERE [WarehouseMgmt].[GetDateTimeFromTimeId](TimeId) >= Dateadd(Month, Datediff(Month, 0, DATEADD(m, -6, current_timestamp)), 0)
GROUP BY DPT.[Name]

Group data by month

I want to group by results of sales by YEAR-MONTH. My current query which does the results looks like :
SELECT Cast(Year(s.datekey) AS VARCHAR(4)) + '-'
+ Cast(Month(s.datekey) AS VARCHAR(2)) AS Mjesec,
e.employeekey,
Sum(s.totalcost) AS SalesAmount
FROM factsales s
INNER JOIN dimstore st
ON s.storekey = st.storekey
INNER JOIN dimemployee e
ON e.employeekey = st.storemanager
WHERE s.datekey BETWEEN '2007-01-01' AND '2007-01-05'
GROUP BY e.employeekey,
Cast(Year(s.datekey) AS VARCHAR(4)) + '-'
+ Cast(Month(s.datekey) AS VARCHAR(2))
ORDER BY employeekey
I am wondering if there are any other better and more elegant way to achieve same results? Perhaps, more friendly format for DateTime in c#?
Much more efficient to strip time by using date math than converting to a string. Also much more efficient to leave the particular string formatting to the end (or better yet, doing it in C# using Format()).
;WITH c AS
(
SELECT m = DATEADD(MONTH, DATEDIFF(MONTH, 0, s.datekey), 0),
e.employeekey, s.totalcost
FROM dbo.factsales AS s
INNER JOIN dbo.dimstore AS st
ON s.storekey = st.storekey
INNER JOIN dimemployee AS e
ON e.employeekey = st.storemanager
WHERE s.datekey >= '20070101' AND s.datekey < '20070106'
),
d AS
(
SELECT m, employeekey, SalesAmount = SUM(totalcost)
FROM c
GROUP BY m, employeekey
)
SELECT
Mjesec = CONVERT(CHAR(7), m, 120),
employeekey,
SalesAmount
FROM d
ORDER BY employeekey;
If you can do the formatting in your app, then you can collapse this to:
;WITH c AS
(
SELECT m = DATEADD(MONTH, DATEDIFF(MONTH, 0, s.datekey), 0),
e.employeekey, s.totalcost
FROM dbo.factsales AS s
INNER JOIN dbo.dimstore AS st
ON s.storekey = st.storekey
INNER JOIN dimemployee AS e
ON e.employeekey = st.storemanager
WHERE s.datekey >= '20070101' AND s.datekey < '20070106'
)
SELECT Mjesec = m, employeekey, SalesAmount = SUM(totalcost)
FROM c
GROUP BY m, employeekey
ORDER BY employeekey;
Or even:
SELECT Mjesec = DATEADD(MONTH, DATEDIFF(MONTH, 0, s.datekey), 0),
e.employeekey, s.totalcost
FROM dbo.factsales AS s
INNER JOIN dbo.dimstore AS st
ON s.storekey = st.storekey
INNER JOIN dimemployee AS e
ON e.employeekey = st.storemanager
WHERE s.datekey >= '20070101' AND s.datekey < '20070106'
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, s.datekey, 0), 0), e.employeekey
ORDER BY employeekey;
Do:
SELECT CONVERT(CHAR(7),s.DateKey,120) AS Mjesec....
FROM ....
GROUP BY CONVERT(CHAR(7),s.DateKey,120)....
ORDER BY EmployeeKey

Order By Case multiple fields

The code below (and numerous codes like it) continues to return blanks.
Basically, if LaborCode = '01 - SC' then it should sort by JobSite, LaborCode, and Schedule (the exact date)
If it's NOT 01 - SC, it should sort by JobSite, LaborCode, and DayNo (the day of the week)
Select Distinct Agreements.AgrmntID, Agreements.Description, Agreements.Status,
JobSites.SiteName, JobSites.Address2, JobSites.City, Customers.CustName,
Customers.CompanyName, LaborCodeTypes.RepairCode As LaborCode, Schedule = Case
LaborCodeTypes.RepairCode
When '01 - SC' Then Left(Convert(varchar,AgreementSchedules.SchedDate,110),
10) Else DateName(dw, AgreementSchedules.SchedDate)
End, Employees1.EmpName As Vendor, Employees.EmpName As [Area Manager],
DatePart(dw, AgreementSchedules.SchedDate) As DayNo
From Agreements Inner Join
Customers On Agreements.CustID = Customers.CustID Inner Join
AgreementSchedules On Agreements.AgrmntID = AgreementSchedules.AgrmntID
Inner Join
JobSites On Agreements.CustSiteID = JobSites.CustSiteID Left Outer Join
LaborCodeTypes On AgreementSchedules.RepairID = LaborCodeTypes.RepairID
Left Outer Join
Employees On AgreementSchedules.FormanEmpID = Employees.EmployeeID Left Join
WorkOrderSchedules On WorkOrderSchedules.ScheduleID =
AgreementSchedules.ScheduleID And AgreementSchedules.ScheduleID =
WorkOrderSchedules.ScheduleID Left Join
WorkOrderScheduleTechs On WorkOrderSchedules.ScheduleID =
WorkOrderScheduleTechs.ScheduleID Left Join
Employees Employees1 On WorkOrderScheduleTechs.EmployeeID =
Employees1.EmployeeID
Where Agreements.Status = 2 And LaborCodeTypes.RepairCode <> 'Vendor Bill' And
Month(AgreementSchedules.SchedDate) = Month(GetDate())
Order By Case
When [LaborCodeTypes.RepairCode] In ('01 - SC') Then JobSites.SiteName +
LaborCodeTypes.RepairCode + Schedule
Else JobSites.SiteName + LaborCodeTypes.RepairCode + DayNo End
Thank you for your help!!
Try this:
ORDER BY JobSites.SiteName,
LaborCodeTypes.RepairCode,
CASE WHEN LaborCodeTypes.RepairCode IN ('01 - SC') THEN Schedule ELSE DayNo END
Okay, in SQL Server:
CREATE PROCEDURE dbo.Agreements_GetList
AS
BEGIN
SET NOCOUNT ON;
SELECT DISTINCT
a.AgrmntID,
a.Description,
a.Status,
js.SiteName,
js.Address2,
js.City,
c.CustName,
c.CompanyName,
LaborCode = lct.RepairCode,
Schedule = CASE lct.RepairCode
WHEN '01 - SC' THEN CONVERT(CHAR(10), aSch.SchedDate, 110)
--------------------^^^ much better than LEFT and not specifying length
ELSE DATENAME(WEEKDAY, aSch.SchedDate) END,
Vendor = e2.EmpName,
[Area Manager] = e1.EmpName,
DayNo = CONVERT(CHAR(1), DATEPART(WEEKDAY, aSch.SchedDate))
--------^^^ this convert is important
FROM dbo.Agreements AS a
INNER JOIN dbo.Customers AS c
ON a.CustID = c.CustID
INNER JOIN dbo.AgreementSchedules AS aSch
ON a.AgrmntID = aSch.AgrmntID
INNER JOIN dbo.JobSites AS js
ON a.CustSiteID = js.CustSiteID
LEFT OUTER JOIN dbo.LaborCodeTypes AS lct
ON aSch.RepairID = lct.RepairID
LEFT OUTER JOIN dbo.Employees AS e1
ON aSch.FormanEmpID = e1.EmployeeID
LEFT OUTER JOIN dbo.WorkOrderSchedules AS w
ON w.ScheduleID = aSch.ScheduleID
LEFT OUTER JOIN dbo.WorkOrderScheduleTechs AS wt
ON w.ScheduleID = wt.ScheduleID
LEFT OUTER JOIN dbo.Employees AS e2
ON wt.EmployeeID = e2.EmployeeID
WHERE
a.Status = 2
AND lct.RepairCode <> 'Vendor Bill'
AND aSch.SchedDate >= DATEADD(MONTH, 0, DATEDIFF(MONTH, 0, GETDATE()))
AND aSch.SchedDate < DATEADD(MONTH, 1, DATEDIFF(MONTH, 0, GETDATE()))
ORDER BY
js.SiteName,
lct.RepairCode,
CASE WHEN lct.RepairCode = '01 - SC'
THEN js.SiteName ELSE DayNo END;
END
GO
Now I have absolutely no knowledge of your application, so you will have to figure out how to call a stored procedure from it instead of embedding SQL.