Query % of x item based on x+y total - sql

I'm running a SQL command which returns me the following table
What I need now, is to retrieve how much % corretiva is from total, and how much % preventiva is from total for each month, so there must be another 2 columns like preventivas% and corretivas% as example, I know MES.1 (month 1), will return preventiva =100%, and corretiva = 0%,
This is my query
SELECT
MONTH(workOrderDate) AS MES,
(SUM(CASE WHEN WorkType = '02' AND workOrderDescription = 'preventiva' THEN 1.0 ELSE 0 END)) AS preventiva,
(SUM(CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END)) AS corretivas,
SUM(CASE WHEN WorkType = '02' AND workOrderDescription = 'preventiva' THEN 1.0 ELSE 0 END + CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END) AS total
FROM
WorkOrder
WHERE
YEAR(workOrderDate) = 2018
AND lastUpdateData IS NOT NULL
GROUP BY
MONTH(workOrderDate);
I can't seem to figure out how to achieve the wanted result, would anyone please help me?
Thanks!

You can take your existing query, put it into a CTE, and then calculate your percentages in the main SELECT, like this:
;WITH subresults AS
(
SELECT
MES = MONTH(workOrderDate)
,preventiva = ( SUM(CASE WHEN WorkType = '02'
AND workOrderDescription = 'preventiva'
THEN 1.0
ELSE 0 END
)
)
,corretivas = ( SUM(CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END))
,total = SUM(CASE WHEN WorkType = '02'
AND workOrderDescription = 'preventiva'
THEN 1.0
ELSE 0 END + CASE WHEN workOrderDescription = 'CORRETIVA' THEN 1 ELSE 0 END
)
FROM WorkOrder
WHERE
YEAR(workOrderDate) = 2018
AND lastUpdateData IS NOT NULL
GROUP BY MONTH(workOrderDate)
)
SELECT
s.MES
,s.preventiva
,s.corretivas
,s.total
,preventivasPct = CASE WHEN s.total <> 0 THEN (s.preventiva / s.total) * 100.0 ELSE NULL END
,corretivasPct = CASE WHEN s.total <> 0 THEN (s.corretivas / s.total) * 100.0 ELSE NULL END
FROM subresults s
EDIT: I added CASE statements to preventivasPct and corretivasPct. When the total is 0, the CASE will return NULL. Feel free to change NULL to some other value if you want. I've found that usually 0 or NULL is the correct answer when encountered with divide-by-zero when calculating percentages.

Related

How Do I Use Case When with Group By statement

I have made a query but it don't give me what i want :
SELECT Designation_projet, COUNT(*) AS [Nb Demande], CASE WHEN Validation = 0 THEN COUNT(*) END AS Validée, CASE WHEN Validation = 1 THEN COUNT(*)
END AS NonValidée, CASE WHEN Commandé = 0 THEN COUNT(*) END AS NonCommandé,
CASE WHEN Commandé <> 0 THEN COUNT(*) END AS Commandé, SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet,Commandé,Validation
Please help me to achieve my gool.
Thanks in advance
You can do this using condition aggregation. That means that the CASE expression is the argument to SUM() -- it goes "inside" not "outside":
SELECT Designation_projet, COUNT(*) AS [Nb Demande],
SUM(CASE WHEN Validation = 0 THEN 1 ELSE 0 END) as Validée,
SUM(CASE WHEN Validation = 1 THEN 1 ELSE 0 END) as NonValidée,
SUM(CASE WHEN Commandé = 0 THEN 1 ELSE 0 END) AS NonCommandé,
SUM(CASE WHEN Commandé <> 0 THEN 1 ELSE 0 END) END AS Commandé,
SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet;
If you want one row per Designation_projet, then that should be the only key in the GROUP BY.
Assuming Validation takes on only two values, you can simplify the first two aggregation expressions:
SELECT Designation_projet, COUNT(*) AS [Nb Demande],
SUM(1 - Validation) as Validée,
SUM(Validation = 1) as NonValidée,
SUM(CASE WHEN Commandé = 0 THEN 1 ELSE 0 END) AS NonCommandé,
SUM(CASE WHEN Commandé <> 0 THEN 1 ELSE 0 END) END AS Commandé,
SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet;
You may be able to simplify the Commandé expressions as well.
Try this
SELECT Designation_projet, COUNT(*) AS [Nb Demande],sum(CASE WHEN Validation = 1 THEN 1 else 0 END AS Validée,sum( CASE WHEN Validation = 1 THEN 1 else 0
END AS NonValidée, sum(CASE WHEN NonCommandé <> 1 THEN 1 else 0 END AS NonCommandé,
sum(CASE WHEN Commandé <> 1 THEN 1 else 0 END AS Commandé, SUM(TotalHT) AS TotalHT
FROM V_DemandeAchat
GROUP BY Designation_projet

Update a complex SQL query to add a new column with the sum of two columns

The below SQL query creates a table with n number of columns named in the next line.
...., curr_amount, tax_amount, ....
I am having a very tough time updating the below query to create a new column called total and position it exactly after tax_amount column and the total column should contain the values that are obtained after sum of curr_amount & tax_amount.
I have been working on this from more than one day but couldn't figure it out.
P.S. Still a noob here. Thanks alot for your time.
.
SELECT Isnull(t.total_month, 'Total') total_month,
t.tax_amount,
t.curr_amount,
t.usage_qty,
t.kh_qty,
t.bill_cnt
FROM (SELECT dbo.Sigmadf(bm.posted_date, 'YYYY-MM') total_month,
Sum(CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END) usage_qty,
Sum(CASE
WHEN bm.curr_amount IS NULL THEN 0
ELSE bm.curr_amount
END) curr_amount,
Sum(CASE
WHEN bm.adj_amount IS NULL THEN 0
ELSE bm.adj_amount
END) adj_amount,
Sum(CASE
WHEN bm.bal_fwd_amount IS NULL THEN 0
ELSE bm.bal_fwd_amount
END) bal_forward,
Sum(CASE
WHEN bm.tax_amount IS NULL THEN 0
ELSE bm.tax_amount
END) tax_amount,
Sum(CASE
WHEN bm.due_amount IS NULL THEN 0
ELSE bm.due_amount
END) due_amount,
Sum(CASE
WHEN bm.last_total_paid_amount IS NULL THEN 0
ELSE bm.last_total_paid_amount * -1
END) paid_amount,
Sum(CASE
WHEN bm.bill_print = 'Y' THEN 1
ELSE 0
END) pdf_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '0' THEN 1
ELSE 0
END) reg_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '1' THEN 1
ELSE 0
END) ftime_cnt,
Sum(CASE
WHEN Isnull(bm.bill_handling_code, '0') = '9999' THEN 1
ELSE 0
END) ltime_cnt,
Count(*) bill_cnt,
Sum(CASE
WHEN bill_status = '01' THEN 1
ELSE 0
END) canc_cnt,
Sum(CASE
WHEN bill_status = '01' THEN
CASE
WHEN rr.usage_qty IS NULL THEN 0
ELSE Cast (rr.usage_qty AS NUMERIC(18, 2))
END
ELSE 0
END) canc_usg,
Sum(CASE
WHEN vis.kh_qty IS NULL THEN 0
ELSE Cast(vis.kh_qty AS NUMERIC(18, 2))
END) kh_qty
FROM bill_master bm WITH (nolock)
INNER JOIN (SELECT bill_no,
Sum(CASE
WHEN vpb.recurr_charge_type IN ( 'T4',
'SLF' )
THEN
CASE
WHEN vpb.print_qty = 'Y'
AND vpb.usage_qty IS NOT NULL
THEN
Cast (vpb.usage_qty AS
NUMERIC(18, 2))
ELSE 0
END
ELSE 0
END) usage_qty
FROM v_print_bills_all vpb
GROUP BY bill_no) rr
ON rr.bill_no = bm.bill_no
LEFT OUTER JOIN vis_bill_master_cr vis WITH (nolock)
ON bm.bill_no = vis.bill_no
WHERE 1 = 1
AND dbo.Trunc(bm.posted_date) >= '20150101'
AND dbo.Trunc(bm.posted_date) <= '20151124'
AND bm.posted_date IS NOT NULL
AND bm.cust_id NOT IN (SELECT cc.code_type cust_id
FROM code_table cc WITH (nolock)
WHERE cc.code_tabname = 'RptExclCust'
AND cc.code_value = 'cust_id')
GROUP BY dbo.Sigmadf(bm.posted_date, 'YYYY-MM') WITH rollup)t
I must say that the explanation is not so clear.
From my understanding, you want the total of two columns.
So, wrap all your query between parenthesis, call it subQuery, and make the sum of the two columns on top:
SELECT subQuery.total_month as bill_date,
subQuery.curr_amount as amount,
subQuery.tax_amount tax,
subQuery.curr_amount + subQuery.tax_amount as [total],
...
FROM
(..your entire query here..) as subQuery

postgresql: SUM with OR operator with an aggregation query

I have successfully done following query:
SELECT rs.personid, rs.rec_count,
sum(case when r.rectype = 'degreeOne' then 1 else 0 end)
but now I want to change this to following
SELECT rs.personid, rs.rec_count,
sum(case when r.rectype = 'test1' then 1 else 0 end) OR sum(case when r.rectype = 'random' and r.badgeid = 'bronze' then 1 else 0 end) as degree_one, ...
basically I want to do sum with an "OR" operator, I tried as I have shown but it gives me an error.
sum (
case
when
r.rectype = 'test1'
or
r.rectype = 'random' and r.badgeid = 'bronze'
then 1
else 0
end
) as degree_one

Avoiding a divide by zero error in a case statement

I am getting a divide by zero error in my script.
Can anyone please help.
I am trying to divide two records and one of them has zero in it. I dont want to lose the row, please advise.
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) as "Paid in 24hrs",
COUNT([MONTH_OF_SUSPENSION])/sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) as "Achieved"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
You can introduce a second case to check the result of the sum:
case
when sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end) > 0
then COUNT([MONTH_OF_SUSPENSION])/sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end)
else 0 /* a default value that makes sense to you */
end as "Achieved"
Looking at your code I could assume you are using MSSQL and therefore you could use nullif which returns null if two arguments are equal. So for example your code could look like :
COUNT([MONTH_OF_SUSPENSION])/nullif(sum(case when [PAYMENT_<=24HRS] = 'Y' then 1 else 0 end),0) as "Achieved"
What it does is if the value of the sum operator is equal 0 then the divisor is turn from zero into null and that will result in the entire equation to become null.
use another case statement to check the result of your sum
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "Paid in 24hrs",
case
when sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) = 0 then 'whatever you want in this case'
else COUNT([MONTH_OF_SUSPENSION])/sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "Achieved"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
although this is pretty nasty looking, so you could tidy it up a bit with a sub-select:
select
year,
month,
request,
PaidIn24hrs,
case
when PaidIn24hrs = 0 then 'whatever you want in this case'
else request/PaidIn24hrs
end as "Achieved"
from
(
select DATEPART(Year,Request_date) as "Year",
DATEPART(Month,Request_date) as "Month",
COUNT([MONTH_OF_SUSPENSION]) as "Request" ,
sum(case
when [PAYMENT_<=24HRS] = 'Y' then 1
else 0
end) as "PaidIn24hrs"
FROM suspension_br
where REQUEST_STATUS = 'OTHERS'
GROUP BY DATEPART(Year,Request_date),DATEPART(Month,Request_date)
)

How do you get the product of two case statements

I am trying to combine case statements using the following code and keep encountering errors.
SELECT
dbo.COL_TBL_WAGES.[Job Group],
SUM(CASE
WHEN COL_V_COST.EMP_TNG_RL_CD = 'ST'
THEN ([CountOfEMP_TNG_STT_DT] *
(WHEN IsNumeric([TBL_VCOURSE.Length])
THEN TBL_VCOURSE ELSE 0 END) AS ST_Hours
It looks like you want this since you have two CASE expressions in your original:
SELECT dbo.COL_TBL_WAGES.[Job Group],
SUM(CASE
WHEN COL_V_COST.EMP_TNG_RL_CD = 'ST'
THEN [CountOfEMP_TNG_STT_DT]
ELSE 0 END
* CASE
WHEN IsNumeric([TBL_VCOURSE.Length]) = 1
THEN TBL_VCOURSE
ELSE 0 END
) AS ST_Hours
Edit, based on your comment your query will be similar to this:
SELECT dbo.COL_TBL_WAGES.[Job Group],
SUM(CASE
WHEN COL_V_COST.EMP_TNG_RL_CD = 'ST'
THEN [CountOfEMP_TNG_STT_DT] ELSE 0 END
* CASE
WHEN IsNumeric([COL_TBL_VCOURSE].[Length]) = 1
THEN COL_TBL_VCOURSE.[LENGTH]
ELSE 0 END) AS ST_Hours,
SUM(CASE
WHEN COL_V_COST.EMP_TNG_RL_CD = 'ST'
THEN [CountOfEMP_TNG_STT_DT]*CAST([2011 Total] AS FLOAT) ELSE 0 END
* CASE
WHEN IsNumeric([COL_TBL_VCOURSE].[LENGTH]) = 1
THEN CAST([COL_TBL_VCOURSE].[LENGTH] AS FLOAT) ELSE 0 END) AS ST_Cost