Follow on - Multiple Sums in SQL Query - sql

Thanks to Quassnoi before who gave me the answer I was looking for - this led to a seperate problem though. Current code:
SELECT i.CONCOM, COALESCE (SUM(t.LOGMINS), 0) AS TotalWithoutNew
FROM INQUIRY AS i INNER JOIN
TIMELOG AS t ON t.INQUIRY_ID = i.INQUIRY_ID INNER JOIN
PROD AS P ON i.PROD_ID = P.PROD_ID INNER JOIN
CATEGORY AS C ON P.CATEGORY_ID = C.CATEGORY_ID
WHERE (DATEPART(month, i.ESCDATE) = DATEPART(month, GETDATE()) - 1) AND (DATEPART(year, i.ESCDATE) = DATEPART(year, DATEADD(m, - 1, GETDATE()))) AND
(C.CATEGORY_ID <> '30')
GROUP BY i.CONCOM
ORDER BY TotalWithoutNew DESC
This brings back exactly what I want (C.CATEGORY_ID <> 30) is not included in the initial column marked as TotalWithoutNew. I also need the value WITH it in as well though. Is there any way to have another column called TotalWithNew that includes all CATEGORY_IDs? I am certain learning a lot of new query language today!

SELECT i.CONCOM,
COALESCE (SUM(CASE WHEN C.CATEGORY_ID = '30' THEN 0 ELSE t.LOGMINS END), 0) AS TotalAllID,
COALESCE (SUM(t.LOGMINS), 0) AS TotalWithoutNew
FROM INQUIRY AS i INNER JOIN
TIMELOG AS t ON t.INQUIRY_ID = i.INQUIRY_ID INNER JOIN
PROD AS P ON i.PROD_ID = P.PROD_ID INNER JOIN
CATEGORY AS C ON P.CATEGORY_ID = C.CATEGORY_ID
WHERE (DATEPART(month, i.ESCDATE) = DATEPART(month, GETDATE()) - 1) AND (DATEPART(year, i.ESCDATE) = DATEPART(year, DATEADD(m, - 1, GETDATE())))
GROUP BY i.CONCOM
ORDER BY TotalWithoutNew DESC
Note: I haven't tried but I hope you get the idea of using CASE WHEN ....

SELECT i.CONCOM
, COALESCE(SUM(CASE WHEN C.CATEGORY_ID <> 30 THEN t.LOGMINS END), 0)
AS TotalWithoutNew
, COALESCE(SUM(t.LOGMINS), 0) AS TotalWithNew
FROM INQUIRY AS i INNER JOIN
TIMELOG AS t ON t.INQUIRY_ID = i.INQUIRY_ID INNER JOIN
PROD AS P ON i.PROD_ID = P.PROD_ID INNER JOIN
CATEGORY AS C ON P.CATEGORY_ID = C.CATEGORY_ID
WHERE (DATEPART(month, i.ESCDATE) = DATEPART(month, GETDATE()) - 1)
AND (DATEPART(year, i.ESCDATE) = DATEPART(year, DATEADD(m, - 1, GETDATE())))
GROUP BY i.CONCOM
ORDER BY TotalWithoutNew DESC

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;

Adding weekdays to select statement

I have a select statement that pulls and consolidates data from multiple tables. I need to add additional logic to calculate the number of weekdays between the createdDt and CallEndDate (but if the callEndDate is null use the current date).
We are using SQL Server 2016 and am at a loss on how to incorporate this additional calculated logic with my select statement below. Any suggestions?
SELECT c.ID, c.CreatedDt, c.LastUpdatedDt, c.CALLSTARTDT, c.CALLENDDT, c.DUEDT,
c.TYPE, c.DESCRIPTION, c.COMMENT, c.CONTRACT, c.DISCLOSUREPTAN, c.DISCLOSURENPI, c.DISCLOSURETIN,
c.DISCLOSUREIVR, c.CALLERFIRSTNAME, c.CALLERLASTNAME, c.CALLERPHONE, c.CALLEREMAIL, c.STATUS,
c.STATUSQUALIFIER, c.RATING, u1.Name as LastUpdatedByName, u2.Name as CreatedByName,
u3.Name as OwnedByName, p.PTAN, p.NPI,p.NAME, con.LOB
FROM Case c
LEFT JOIN ossys_User u1 ON c.LastUpdatedBy = u1.Id
LEFT JOIN ossys_User u2 ON c.CreatedBy = u2.ID
LEFT JOIN ossys_User u3 ON c.OwnedBy = u3.Id
INNER JOIN PROVIDER p ON c.TargetId = p.Id
INNER JOIN CONTRACTS con ON p.Contract = con.Contract
WHERE
c.LastUpdatedDt BETWEEN '2019-01-01' AND '2019-07-01'
Order By c.CreatedDt ASC
Calculations can be included in your select statement as such:
SELECT c.ID, c.CreatedDt, c.LastUpdatedDt, c.CALLSTARTDT, c.CALLENDDT, c.DUEDT,
c.TYPE, c.DESCRIPTION, c.COMMENT, c.CONTRACT, c.DISCLOSUREPTAN,
c.DISCLOSURENPI,c.DISCLOSURETIN,c.DISCLOSUREIVR, c.CALLERFIRSTNAME, c.CALLERLASTNAME,
c.CALLERPHONE, c.CALLEREMAIL, c.STATUS, c.STATUSQUALIFIER, c.RATING,
u1.Name as LastUpdatedByName, u2.Name as CreatedByName,
u3.Name as OwnedByName,
p.PTAN, p.NPI,p.NAME,
con.LOB,
((DATEDIFF(dd, c.CreateDt, ISNULL(c.CALLENDDT,#GETDATE)) + 1)
-(DATEDIFF(wk, c.CreateDt, ISNULL(c.CALLENDDT,#GETDATE)) * 2)
-(CASE WHEN DATENAME(dw, c.CreateDt) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, ISNULL(c.CALLENDDT, #GETDATE)) = 'Saturday' THEN 1 ELSE 0 END))
As diff
FROM Case c
LEFT JOIN ossys_User u1 ON c.LastUpdatedBy = u1.Id
LEFT JOIN ossys_User u2 ON c.CreatedBy = u2.ID
LEFT JOIN ossys_User u3 ON c.OwnedBy = u3.Id
INNER JOIN PROVIDER p ON c.TargetId = p.Id
INNER JOIN CONTRACTS con ON p.Contract = con.Contract
WHERE
c.LastUpdatedDt BETWEEN '2019-01-01' AND '2019-07-01'
Order By c.CreatedDt ASC
Although I would more likely go with the solution defined by the link posted by #openshac and put that into a function before calling as such.
CREATE FUNCTION [dbo].fn_CountWeekDays
(
#fromdate Datetime,
#todate Datetime
)
RETURNS TABLE AS RETURN
(
SELECT
(DATEDIFF(dd, #fromdate, #todate) + 1)
-(DATEDIFF(wk, #fromdate, #todate) * 2)
-(CASE WHEN DATENAME(dw, #fromdate) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, #todate) = 'Saturday' THEN 1 ELSE 0 END)
As NoOfWeekDays
)
GO
SELECT c.ID, c.CreatedDt, c.LastUpdatedDt, c.CALLSTARTDT, c.CALLENDDT, c.DUEDT,
c.TYPE, c.DESCRIPTION, c.COMMENT, c.CONTRACT, c.DISCLOSUREPTAN,
c.DISCLOSURENPI,c.DISCLOSURETIN,c.DISCLOSUREIVR, c.CALLERFIRSTNAME, c.CALLERLASTNAME,
c.CALLERPHONE, c.CALLEREMAIL, c.STATUS, c.STATUSQUALIFIER, c.RATING,
u1.Name as LastUpdatedByName, u2.Name as CreatedByName,
u3.Name as OwnedByName,
p.PTAN, p.NPI,p.NAME,
con.LOB,
CountWeekDays(c.CreateDt, ISNULL(c.CALLENDDT,#GETDATE))
As diff
FROM Case c
LEFT JOIN ossys_User u1 ON c.LastUpdatedBy = u1.Id
LEFT JOIN ossys_User u2 ON c.CreatedBy = u2.ID
LEFT JOIN ossys_User u3 ON c.OwnedBy = u3.Id
INNER JOIN PROVIDER p ON c.TargetId = p.Id
INNER JOIN CONTRACTS con ON p.Contract = con.Contract
WHERE
c.LastUpdatedDt BETWEEN '2019-01-01' AND '2019-07-01'
Order By c.CreatedDt ASC

SQL Server - Subtracting results of two SQL Queries

I'm trying to results of two queries using Subquery in SQL Server.
What I'm trying to achieve is to Calculate number of customers that are part of "ProductX Promotion" and subtract the count of customers that are part of "ProductX Promotion" and have actually purchased ProductX within last 60 days. This gives me the count of enrolled customers who have not made ProductX purchase for better insights for marketing.
Initially I only had COUNT() hence it was easy to subtract the two. Now requirement is that the count broken down by State and Zip level of the customer. The problem arises here as I cannot use direct Subtraction, I tried NOT EXISTS but didn't work, I tried JOINs but still no luck. I know the solution is pretty simple but I cannot think of any.
Here's the original code with comments on what particular columns mean,
SELECT
(SELECT COUNT (DISTINCT (c.CustomerNumber))
FROM Customer c
INNER JOIN
TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber
WHERE c.ProductXPref = 1 --Indicates if Customer was part of ProductX promotion program.
AND t.TransactionDate > DATEADD(d, -60, getdate()))
-
(SELECT COUNT (DISTINCT c.CustomerNumber)
FROM Customer c
INNER JOIN
TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber
WHERE t.ProductXIndicator = 1 --Indicates if ProductX was purchased
AND t.TransactionDate > DATEADD(DD, -60, getdate())
AND c.ProductXPref = 1 --Indicates if Customer was part of ProductX promotion program.
) AS 'Column Name' INTO #TempTable1
Here's what I'm trying to implement,
SELECT
(SELECT c.Zip, c.State, COUNT (DISTINCT (c.CustomerNumber))
FROM Customer c
INNER JOIN
TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber
WHERE c.ProductXPref = 1
AND t.TransactionDate > DATEADD(d, -60, getdate())
GROUP BY c.Zip, c.State)
-
(SELECT c.Zip, c.State, COUNT (DISTINCT c.CustomerNumber)
FROM Customer c
INNER JOIN
TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber
WHERE t.ProductXIndicator = 1
AND t.TransactionDate > DATEADD(DD, -60, getdate())
AND c.ProductXPref = 1
GROUP BY c.Zip, c.State) AS 'Column Name' INTO #TempTable1
This is the error I see,
Msg 116, Level 16, State 1, Line 129
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Any pointers will help. Thanks.
I think you are making this much more complicated than it needs to be -- the first query can be written as
SELECT COUNT(DISTINCT c.CustomerNumber)
FROM Customer c
INNER JOIN TransactionDetail t ON c.CustomerNumber = t.CustomerNumber
WHERE
c.ProductXPref = 1 --Indicates if Customer was part of ProductX promotion program.
AND t.TransactionDate > DATEADD(d, -60, getdate()))
AND t.ProductXIndicator <> 1
As you can see if you just don't include these rows in the original count it is the same as doing another query and subtracting.
So the second is simply
SELECT c.Zip, c.State, COUNT(DISTINCT c.CustomerNumber)
FROM Customer c
INNER JOIN TransactionDetail t ON c.CustomerNumber = t.CustomerNumber
WHERE
c.ProductXPref = 1 --Indicates if Customer was part of ProductX promotion program.
AND t.TransactionDate > DATEADD(d, -60, getdate()))
AND t.ProductXIndicator <> 1
GROUP BY c.Zip, c.State
This should work:
SELECT
c.Zip, c.State,COUNT (DISTINCT c.CustomerNumber)
FROM
Customer c
INNER JOIN TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber AND
c.ProductXPref = 1 --Indicates if Customer was part of ProductX promotion program.
AND t.TransactionDate > DATEADD(DD, -60, getdate())
WHERE t.ProductXIndicator <> 1
GROUP BY c.Zip, c.State
after some validation the numbers did not match what I expect those to be, hence I have tried different logic which worked fine and returned what I wanted. So posting the answer here, again thanks for all the help.
SELECT d.State, d.Zip, COUNT(DISTINCT(d.CustomerNumber)) AS 'Active Customers'
INTO #ProductDifference
FROM Customer c
INNER JOIN
TransactionDetail t
ON
c.CustomerNumber = t.CustomerNumber
WHERE d.ProductXPref = 1
AND t.TransactionDate > DATEADD(d, -60, getdate())
AND c.CustomerNumber
NOT IN
(SELECT DISTINCT d.[CustomerNumber]
FROM Customer d
INNER JOIN
TransactionDetail f
ON
d.CustomerNumber = f.CustomerNumber
WHERE f.ProductXIndicator = 1
AND f.TransactionDate > DATEADD(DD, -60, getdate())
AND d.ProductXPref = 1)
GROUP BY c.State, c.Zip

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.

can i pivot this entire query to return different results?

This query is returning exactly what i need but im trying to create a pivot table out of it as well. I want to be able to SUM the column defined as SLAStatus in the CASE clause (dont know if thats even possible) as well as count the OrderID column as well as calculate(sum of SLAStatus column)/(Count of OrderID Column) to return a percentage of orders withing SLA. Been looking online everywhere but cant seem to figure this out
SELECT oi.OrderID, o.Address1 as StreetAddress, c.Name as County, o.State, p.Abbreviation, oi.OrderDate as Dateentered,
DATEADD(dd, DATEDIFF(dd, 0, oi.DeliveredDate), 0) as DateCompleted, DATEADD(dd, DATEDIFF(dd, 0, oi.RequiredByDate), 0) as EstimatedDeliveryDate,
CASE
WHEN oi.DeliveredDate <= oi.RequiredByDate THEN '1'
ELSE '0'
END AS SLAStatus,
cl.Name as Client, clb.Name as Client2, v.ContactFirstName + ' ' + v.ContactLastName as Appraiser
FROM OrderItems oi
JOIN Orders o on o.OrderID = oi.OrderID
JOIN Counties c on c.FIPS = o.FIPS
JOIN Products p on p.ProductID = oi.ProductID
JOIN Clients cl on cl.ClientID = o.ClientID
JOIN ClientBranches clb on clb.ClientID = cl.ClientID
JOIN Vendors v on v.VendorID = oi.VendorID
JOIN Milestones m on m.MilestoneID = oi.LastMilestoneID
WHERE cl.Name not like '%TEST%'
and '2012-03-01' <=
(select MAX(MilestoneDate)
from OrderItemMilestones
where OrderID = oi.OrderID
and OrderItemID = oi.OrderItemID
and MilestoneID in (100,130,140,150))
and '2012-04-10' >=
(select MAX(MilestoneDate)
from OrderItemMilestones
where OrderID = oi.OrderID
and OrderItemID = oi.OrderItemID
and MilestoneID in (100,130,140,150))
I would recommend using a common table expression (CTE). Just wrap your original query in a CTE then you can do the grouping you are looking for.
with originalCTE as
(
SELECT oi.OrderID, o.Address1 as StreetAddress, c.Name as County, o.State,
p.Abbreviation, oi.OrderDate as Dateentered,
DATEADD(dd, DATEDIFF(dd, 0, oi.DeliveredDate), 0) as DateCompleted, DATEADD(dd,
DATEDIFF(dd, 0, oi.RequiredByDate), 0) as EstimatedDeliveryDate,
CASE
WHEN oi.DeliveredDate <= oi.RequiredByDate THEN '1'
ELSE '0'
END AS SLAStatus,
cl.Name as Client, clb.Name as Client2, v.ContactFirstName + ' ' + v.ContactLastName as Appraiser
FROM OrderItems oi
JOIN Orders o on o.OrderID = oi.OrderID
JOIN Counties c on c.FIPS = o.FIPS
JOIN Products p on p.ProductID = oi.ProductID
JOIN Clients cl on cl.ClientID = o.ClientID
JOIN ClientBranches clb on clb.ClientID = cl.ClientID
JOIN Vendors v on v.VendorID = oi.VendorID
JOIN Milestones m on m.MilestoneID = oi.LastMilestoneID
WHERE cl.Name not like '%TEST%'
and '2012-03-01' <=
(select MAX(MilestoneDate)
from OrderItemMilestones
where OrderID = oi.OrderID
and OrderItemID = oi.OrderItemID
and MilestoneID in (100,130,140,150))
and '2012-04-10' >=
(select MAX(MilestoneDate)
from OrderItemMilestones
where OrderID = oi.OrderID
and OrderItemID = oi.OrderItemID
and MilestoneID in (100,130,140,150))
)
select sum(SLAStatus), sum(SLAStatus) / count(orderID)
from originalCTE;
If I understand correctly what you are looking for, then that is how I would do it. Hope this helps.