SQL Sum MTD & YTD - sql

I have only just started looking into SQL.
I have a SQL Server 2008 r2 database that will return two fields DocDate & InvValue. I need to sum the InvValues as MTD & YTD as of Today's Date So it looks like
**Period** /////// **Total value**
MTD ////////////111111.11
YTD /////////////999999.99
I have done a fair amount of Googling and can do one or the other with SUM & DATEPART, but I am stuck with trying to do both.
Can someone give me some pseudo-code that would help me google a little further.
Thank you #Gordon Linoff, That helped a lot and I learned something, That I will find useful in the future.
My code now looks like:
SELECT
SUM(CASE WHEN YEAR(T1.[DocDate]) = YEAR(GETDATE()) THEN T0.[TotalSumSy] END) AS YTD,
SUM(CASE WHEN YEAR(T1.[DocDate]) = YEAR(GETDATE()) AND MONTH(T1.[DocDate]) = MONTH(GETDATE()) THEN T0.[TotalSumSy] END) AS MTD
FROM [dbo].[INV1] T0 INNER JOIN [dbo].[OINV] T1 ON T1.[DocEntry] = T0.[DocEntry]
However I now get
YTD.........MTD
99999.99....111111.11
And I need
YTD........99999.99
MTD........11111.11
Any further assistance would be appreciated.

You can do this with conditional aggregation:
select sum(case when year(docdate) = year(getdate()) then InvValue end) as YTD,
sum(case when year(docdate) = year(getdate()) and month(docdate) = month(getdaate())
then InvValue
end) as MTD
from table t;
This assumes you have no future dates in the table. If you do, add in docdate < getdate() to both clauses.
EDIT:
If you need this in two rows, you can simply do this:
select (case when n.n = 1 then 'YTD' else 'MTD' end) as which,
(case when n.n = 1 then YTD else MTD end) as value
from (select sum(case when year(docdate) = year(getdate()) then InvValue end) as YTD,
sum(case when year(docdate) = year(getdate()) and month(docdate) = month(getdaate())
then InvValue
end) as MTD
from table t
) cross join
(select 1 as n union all select 2) n;

SELECT
Period = 'MTD',
Total_value = SUM(T0.TotalSumSy)
FROM dbo.INV1 T0
INNER JOIN dbo.OINV T1
ON T1.DocEntry = T0.DocEntry
WHERE
T1.DocDate >= DATEADD(month,DATEDIFF(month,'20010101',GETDATE()),'20010101')
AND
T1.DocDate < DATEADD(month,1+DATEDIFF(month,'20010101',GETDATE()),'20010101')
UNION ALL
SELECT
'YTD',
SUM(T0.TotalSumSy)
FROM dbo.INV1 T0
INNER JOIN dbo.OINV T1
ON T1.DocEntry = T0.DocEntry
WHERE
T1.DocDate >= DATEADD(year,DATEDIFF(year,'20010101',GETDATE()),'20010101')
AND
T1.DocDate < DATEADD(year,1+DATEDIFF(year,'20010101',GETDATE()),'20010101') ;
The (complicated) conditions at the WHERE clauses are used instead of the YEAR(column) = YEAR(GETDATE() and the other you had previously, so indexes can be used. WHen you apply a function to a column, you make indexes unsuable (with some minor exceptions for some functions and some verios of SQL-Server.) So, the best thing is to try to convert the conditions to this type:
column <operator> AnyComplexFunction()

Related

Combine Three Grouped Select Queries Into One

--ON TIME PMWO's
SELECT LOCATION, COUNT(WONUM) AS OnTimePMWOs
FROM
WORKORDER
WHERE worktype = 'pm' and actfinish<=targcompdate
GROUP BY LOCATION
--PAST DUE PMWO'S
SELECT LOCATION, COUNT(WONUM) AS PastDuePMWOs
FROM
WORKORDER
WHERE worktype = 'pm' and actfinish>=targcompdate
GROUP BY LOCATION
--30 DayForecast-
SELECT W.location, COUNT(W.wonum) AS Forecast30days
from
workorder AS W
INNER JOIN PMFORECAST AS P
ON W.CHANGEDATE=P.CHANGEDATE
WHERE WORKTYPE='PM' AND P.forecastdate>= GETDATE()+30
GROUP BY LOCATION
This is an answer (all be it just a guess based on the limited question). I'm not a fan of placing CASE statements inside aggregates, but depending on environment, indexing, and data in the included tables, it might perform okay. Please be more involved when posting things. Show us what you've tried, explain the problem, give samples of data, include the desired output, all that fun stuff. The better the question, the better chance of a good answer. Okay, done on the high horse...
DECLARE #Forecast30days DATE
SET #Forecast30days = CURRENT_TIMESTAMP + 30
SELECT
wo.LOCATION
,COUNT(CASE WHEN wo.actfinish <= wo.targcompdate THEN wo.WONUM ELSE NULL END) AS OnTimePMWOs
,COUNT(CASE WHEN wo.actfinish >= wo.targcompdate THEN wo.WONUM ELSE NULL END) AS PastDuePMWOs
,COUNT(CASE WHEN pm.changedate IS NOT NULL THEN wo.WONUM ELSE NULL END) AS Forecast30days
FROM WORKORDER AS wo
LEFT JOIN PMFORECAST AS pm
ON wo.changedate = pm.changedate
AND pm.forecastdate >= #Forecast30days
WHERE wo.worktype = 'pm'
AND ((wo.actfinish IS NOT NULL AND wo.targcompdate IS NOT NULL)
OR (pm.changedate IS NOT NULL))
GROUP BY
wo.LOCATION

How do I include records in a Summary query to include those that don't have data?

I have a query on a transaction table that returns the Summarized total on a column for each ID based on a data range. The query works great except it doesn't include those IDs that don't have data in the transaction table. How can I include those IDs in my result filled with a zero total. Here's a simplified version of my query.
SELECT tblID.IDName
,SUM(CASE
WHEN tblTransactions.idxTransType = 30
THEN CAST(tblTransactions.TimeAmount AS FLOAT) / 60.0
ELSE 0
END) AS 'Vacation'
FROM tblTransactions
INNER JOIN tblTransTypes ON tblTransactions.idxTransType = tblTransTypes.IdxTransType
INNER JOIN tblID ON tblTransactions.idxID = tblID.IdxID
WHERE (tblTransactions.Deleted = 0)
AND (tblTransactions.NotCurrent = 0)
AND (tblTransactions.TransDate >= CONVERT(DATETIME, 'March 1, 2018', 102))
AND (tblTransactions.TransDate <= CONVERT(DATETIME, 'April 11, 2018', 102))
GROUP BY tblID.IDName
Actually it's slightly more complicated than that:
SELECT
i.IDName,
SUM(CASE WHEN t.idxTransType = 30 THEN CAST(t.TimeAmount AS FLOAT) / 60.0 ELSE 0 END) AS 'Vacation'
FROM
tblID i
LEFT JOIN tblTransactions t ON t.idxID = i.IdxID AND t.Deleted = 0 AND t.NotCurrent = 0 AND t.TransDate BETWEEN '20180301' AND '20180411'
LEFT JOIN tblTransTypes tt ON tt.IdxTransType = t.idxTransType
GROUP BY
i.IDName;
You want left joins:
SELECT i.IDName,
SUM(CASE WHEN t.idxTransType = 30 THEN CAST(t.TimeAmount AS Float) / 60.0 ELSE 0 END) AS Vacation
FROM tblID i LEFT JOIN
tblTransactions t
ON t.idxID = i.IdxID AND
t.Deleted = 0 AND
t.NotCurrent = 0 AND
t.TransDate >= '2018-03-01' AND
t.TransDate <= '2018-04-11'
tblTransTypes tt
ON t.idxTransType = tt.IdxTransType
GROUP BY i.IDName;
Notes:
Table aliases make the query much easier to write and to read.
Use ISO/ANSI standard date formats.
The filter conditions on all but the first table belong in the ON clauses.

Revenue for two months date wise

I am trying to get data for last 2 month ...but the query does not give perfect result....
SELECT DAY(table_A.PaymentDate) as date1 ,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP) - 1
then CAST(SUM(table_A.Total_Amount) AS INT)
else 0
end) AS last_month_CNT,
(case when MONTH(table_A.PaymentDate) = MONTH(CURRENT_TIMESTAMP)
then CAST(SUM(table_A.Total_Amount) As INT)
else 0
end) as This_month_CNT
FROM Tbl_Pan_Paymentdetails table_A
FULL OUTER JOIN Tbl_Pan_Paymentdetails table_B
ON table_A.PaymentDate=table_B.PaymentDate
WHERE YEAR(table_A.PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND
table_A.PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY
DAY(table_A.PaymentDate) ,MONTH(table_A.PaymentDate)
order by
DAY(table_A.PaymentDate);
Move the entire case expression inside the sum function and don't include the month in the group by. Also, the full outer join seems unnecessary so I removed it.
This should be what you are looking for:
SELECT
DAY(PaymentDate) as date1 ,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP)-1 THEN CAST(Total_Amount AS INT) ELSE 0 END) AS last_month_CNT,
SUM(CASE WHEN MONTH(PaymentDate) = MONTH(CURRENT_TIMESTAMP) THEN CAST(Total_Amount AS INT) ELSE 0 END) AS This_month_CNT
FROM Tbl_Pan_Paymentdetails
WHERE YEAR(PaymentDate) = YEAR(CURRENT_TIMESTAMP)
AND PaymentDate >= DATEADD(MONTH, -1, GETDATE())
GROUP BY DAY(PaymentDate)
ORDER BY DAY(PaymentDate);

Combining groups in GROUP BY

I have a query that groups by the field description. (There are 9 total descriptions.) I need to somehow combine 3 of these descriptions into one group, giving me a total of 7 descriptions. I'm brand new to sql querying, so I'm fairly lost on anything beyond JOINS and WHERE clauses so far. I appreciate the help.
SELECT serviceclass.description, DATEPART(Year, meterread.readdate) AS Year, DATEPART(Month, meterread.readdate) AS Month, SUM(meterread.consumption)
AS Consumption, COUNT(DISTINCT accountservice.account_id) AS Locations
FROM accountservice INNER JOIN
serviceclass ON accountservice.serviceclass_id = serviceclass.serviceclass_id INNER JOIN
meterread ON accountservice.accountservice_id = meterread.accountservice_id
WHERE (#Year = DATEPART(Year, meterread.readdate))
GROUP BY serviceclass.description, DATEPART(Year, meterread.readdate), DATEPART(Month,meterread.readdate)
ORDER BY Year, Month
You can achieve this by using a CASE statement.
replace serviceclass.desription in your SELECT and GROUP BY clauses with
CASE
WHEN serviceclass.description IN ('Desc1','Desc2','Desc3')
THEN 'JointDescription'
ELSE serviceclass.description
END
and also update the Desc 1 ~ 3 with your three description and updated the joint description to what you want it to be.
RESULT:
SELECT CASE
WHEN serviceclass.description IN ('Desc1','Desc2','Desc3')
THEN 'JointDescription'
ELSE serviceclass.description
END as description,
DATEPART(Year, meterread.readdate) AS Year,
DATEPART(Month, meterread.readdate) AS Month,
SUM(meterread.consumption) AS Consumption,
COUNT(DISTINCT accountservice.account_id) AS Locations
FROM accountservice
INNER JOIN serviceclass ON accountservice.serviceclass_id = serviceclass.serviceclass_id
INNER JOIN meterread ON accountservice.accountservice_id = meterread.accountservice_id
WHERE (#Year = DATEPART(Year, meterread.readdate))
GROUP BY CASE
WHEN serviceclass.description IN ('Desc1','Desc2','Desc3')
THEN 'JointDescription'
ELSE serviceclass.description
END,
DATEPART(Year, meterread.readdate),
DATEPART(Month,meterread.readdate)
ORDER BY Year, Month
You would typically do this with a case statement that would go in both the select and group by statements. Something like:
select (case when serviceclass.description = 'A' then 'B'
else serviceclass.description
end) as description
. . . -- fill in with query here
group by (case when serviceclass.description = 'A' then 'B'
else serviceclass.description
end), . . . -- rest of query goes here

SQL Query: Cannot perform aggregate functions on sub queries

I have the following SQL query
SELECT
[Date],
DATENAME(dw,[Date]) AS Day,
SUM(CASE WHEN ChargeCode IN (SELECT ChargeCode FROM tblChargeCodes WHERE Chargeable = 1) THEN Units ELSE 0 END) ChargeableTotal,
SUM(CASE WHEN ChargeCode IN (SELECT ChargeCode FROM tblChargeCodes WHERE Chargeable = 0) THEN Units ELSE 0 END) NotChargeableTotal,
SUM(Units) AS TotalUnits
FROM
tblTimesheetEntries
WHERE
UserID = 'PJW'
AND Date >= '2013-01-01'
GROUP BY
[Date]
ORDER BY
[Date] DESC;
But I get the error message:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Because I am using sub queries in the Case Else Summation.
How can I revise my query to get 2 x Sums of [Units] one for Chargeable = true, and one for Chargeable = false, even though the Chargeable field is in a different table to all the other information. The two tables are linked by ChargeCode which appears in both tblTimesheetEntries and tblChargeCodes.
Have you tried joining the tables on the chargeCode:
SELECT e.[Date],
DATENAME(dw,e.[Date]) AS Day,
SUM(CASE WHEN c.Chargeable = 1 THEN e.Units ELSE 0 END) ChargeableTotal,
SUM(CASE WHEN c.Chargeable = 0 THEN e.Units ELSE 0 END) NotChargeableTotal,
SUM(e.Units) AS TotalUnits
FROM tblTimesheetEntries e
LEFT JOIN tblChargeCodes c
on e.ChargeCode = c.ChargeCode
WHERE e.UserID = 'PJW'
AND e.Date >= '2013-01-01'
GROUP BY e.[Date]
ORDER BY e.[Date] DESC;