How to use count using case statements - sql

I am trying to get the total number of items and categorize them using case statements. However, I keep getting the items (which are now categorized as "inv") repeated (e.g. "clothes" is repeated 4 times, each with a count of 1 instead of just once with the total count of 4) - how do I get rid of that? I included the desired outcome below.
Here's my table:
TABLE BOX1
ITEM_NO ITEM DATE
===================================
3130C MARVEL_SHIRT 01-JAN-17
1845C SPONGEBOB_BOXERS 03-DEC-18
A900C CK_COAT 04-DEC-18
A988C RIDER_JEANS 11-JAN-19
L350T BARBIE 23-NOV-18
L129T LEGO 09-OCT-18
LXZYT BATMAN_FIG1 12-JAN-19
My code:
select (case substr (item_no,5,1)
when 'C' then 'clothes'
when 'T' then 'toys' else 'misc' end) inv,
count(item_no) total
from box1 where date <= sysdate
group by item
Desired Outcome:
INV TOTAL
===============
CLOTHES 4
TOYS 3

You need to group by your categories.
SELECT CASE substr(item_no, 5, 1)
WHEN 'C' THEN
'clothes'
WHEN 'T' THEN
'toys'
ELSE
'misc'
END inv,
count(item_no) total
FROM box1
WHERE date <= sysdate
GROUP BY CASE substr(item_no, 5, 1)
WHEN 'C' THEN
'clothes'
WHEN 'T' THEN
'toys'
ELSE
'misc'
END;

Becasue of the nature of your expression, you only need to aggregate on substr():
select (case substr(item_no, 5, 1)
when 'C' then 'clothes'
when 'T' then 'toys'
else 'misc'
end) inv,
count(item_no) total
from box1
where date <= sysdate
group by substr(item_no, 5, 1);

Related

Combine 2 queries together

I am struggling to work out combining a query that should give me 3 columns of Month, total_sold_products and drinks_sold_products
Query 1:
Select month(date), count(id) as total_sold_products
from Products
where date between '2022-01-01' and '2022-12-31'
Query 2
Select month(date), count(id) as drinks_sold_products
from Products where type = 'drinks' and date between '2022-01-01' and '2022-12-31'
I tried the union function but it summed count(id) twice and gave me only 2 columns
Many thanks!
Union is for attaching sets of data on top of each other. You need conditional aggregation or a join. See below.
SELECT MONTH(date),
COUNT(*) AS total_sold_products,
COUNT(CASE WHEN type = 'drinks' THEN 1 ELSE 0 END) AS drinks_sold_products,
FORMAT((CASE
WHEN COUNT(*) > 0 THEN
COUNT(CASE WHEN type = 'drinks' THEN 1 ELSE 0 END)/COUNT(*)
ELSE 0 END),
'P') AS Percentage
FROM Products
WHERE date BETWEEN'2022-01-01' AND '2022-12-31'
GROUP BY MONTH(date)

Oracle APex calculate profit on rendering

I have an interactive grid with fixed rows and need to calculate the formula on pre-rendering.
So the source query is:
select kpi,monthly,yearly from kpi where project_id = :P1_PROJECT_ID;
I need to modify this so that the row where kpi='Gross' is calculated on rendering.
It looks in the grid like:
Expected result:(Gross=Profit/Loss)
I am trying to write sql query but it doesn;t work.
Despite data it returns null.
What am i doing wrong here?
select kpi,
case when KPI='Gross'
then to_char(case when KPI='Profit' then to_number(replace(nvl(monthly,0),',','')) end /
case when KPI='Loss' then to_number(replace(nvl(monthly,0),',','')) end ,'999,999,999,999')
else to_char( monthly,'999,999,999,999') end as monthly,
case when KPI='Gross'
then to_char(case when KPI='Profit' then to_number(replace(nvl(yearly,0),',','')) end /
case when KPI='Loss' then to_number(replace(nvl(yearly,0),',','')) end ,'999,999,999,999')
else to_char( yearly,'999,999,999,999') end as yearly,
from kpi where project_id = :P1_PROJECT_ID;
To_char is used to display values as comma separated.
So it would when KPI=Gross, it will divide the columns where kpi=profit by kpi=Loss and dispaly result.
Also the result in the row where KPI=Gros should also have % concatenated.
Apex 20.2
How can this be achieved?
You were close, but you need to use window functions. Without using window functions, the query will not look at the other rows in the case statements to calculate the GROSS column.
The query below is how to properly calculate the GROSS using window functions. I have added ROUND to round the gross to an integer, but you can remove that if you want the decimal points.
WITH
kpi (pk,
kpi,
monthly,
yearly,
project_id)
AS
(SELECT 1, 'Revenue', 60000, 2000000, 1 FROM DUAL
UNION ALL
SELECT 2, 'Profit', 20, 30, 1 FROM DUAL
UNION ALL
SELECT 3, 'Loss', 10, 50, 1 FROM DUAL
UNION ALL
SELECT 4, 'Gross', NULL, NULL, 1 FROM DUAL)
SELECT k.kpi,
CASE k.kpi
WHEN 'Gross'
THEN
ROUND (
SUM (CASE k.kpi WHEN 'Profit' THEN k.monthly ELSE 0 END)
OVER (PARTITION BY project_id)
/ SUM (CASE k.kpi WHEN 'Loss' THEN k.monthly ELSE 0 END)
OVER (PARTITION BY project_id))
|| '%'
ELSE
TO_CHAR (k.monthly)
END AS monthly,
CASE k.kpi
WHEN 'Gross'
THEN
ROUND (
SUM (CASE k.kpi WHEN 'Profit' THEN k.yearly ELSE 0 END)
OVER (PARTITION BY project_id)
/ SUM (CASE k.kpi WHEN 'Loss' THEN k.yearly ELSE 0 END)
OVER (PARTITION BY project_id))
|| '%'
ELSE
TO_CHAR (k.yearly)
END AS yearly
FROM kpi k
WHERE project_id = 1;
KPI MONTHLY YEARLY
__________ __________ __________
Revenue 60000 2000000
Profit 20 30
Loss 10 50
Gross 2% 1%

How to get and unite spesific amount using where clause and make this 3 times in one table

SELECT OfferSK, DateSK, UsedAmount, PaidAmount, ChargedAmount
FROM
(SELECT OfferSK, DateSK, Amount as UsedAmount
FROM dwh.FactExtraExpenses
where FinOperationSK = 2
UNION ALL
SELECT OfferSK, DateSK, Amount as PaidAmount
FROM dwh.FactExtraExpenses
where FinOperationSK = 1
UNION ALL
SELECT OfferSK, DateSK, Amount as ChargedAmount
FROM dwh.FactExtraExpenses
where FinOperationSK in (3, 4, 5, 6, 7, 10)) FCP
order by DateSK
Hello, in one column (Amount) in one table (FactExtraExpenses) I have amounts for different cases like used amount (FinOperationSK = 2) or paid amount(FinOperationSK = 1) or some fee/interst (FinOperationSK in (3,4,5,6,7,10)). Im trying to take all in one table, ordered by day by day (DateSK) for every customer (OfferSK). So i do something but is not ok :) Can you help me?
I think you want conditional aggregation:
select OfferSK, DateSK,
sum(case when FinOperationSK = 2 then Amount else 0 end) as UsedAmount,
sum(case when FinOperationSK = 1 then Amount else 0 end) as PaidAmount,
sum(case when in (3, 4, 5, 6, 7, 10) then Amount else 0 end) as ChargedAmount
from dwh.FactExtraExpenses
group by OfferSK, DateSK;

Need to calculate Year wise sum in the desired output format below, but I am getting column wise data

I just need to know that how can I get the row wise- year totals.
Here is my code and need to get the below expected result :
SELECT /*+parallel(v,32) +parallel(mm,32) +parallel(c,32) */
'BUS' VEH_TYPE,
MM.MAKE_MO,
SUM (CASE WHEN SUBSTR (V.YEAR_Val, 1, 4) = '1990' THEN 1 ELSE 0 END)
AS FY1990,
SUM (CASE WHEN SUBSTR (V.YEAR_VAL, 1, 4) = '1991' THEN 1 ELSE 0 END)
AS FY1991,
SUM (CASE WHEN SUBSTR (V.YEAR_VAL, 1, 4) = '1992' THEN 1 ELSE 0 END)
AS FY1992,
SUM (CASE WHEN SUBSTR (V.YEAR_VAL, 1, 4) = '1993' THEN 1 ELSE 0 END)
AS FY1993,
SUM (CASE WHEN SUBSTR (V.YEAR_VAL, 1, 4) = '1994' THEN 1 ELSE 0 END)
AS FY1994,
SUM (CASE WHEN SUBSTR (V.YEAR_VAL, 1, 4) = '1995' THEN 1 ELSE 0 END)
AS FY1995,
COUNT (MM.MAKE_MO) Total_Count
FROM VEHICLE V, MAKE mm, CATEGORY c
WHERE C.MAKE_MO = mm.MAKE_MO
AND c.CATEGORY_CD = v.CATEGORY_CD
AND V.p_MONTH BETWEEN '199001' AND '199501' --using this as data is huge
AND C.TYPE_CODE=01
AND MM.VEH_CODE='B'
GROUP BY 'BUS,'MM.MAKE_MO, V.YEAR_Val
ORDER BY V.YEAR_Val;
This is the Expected Result :
VEH TYPE YEAR MODEL TOTAL
------- ----- --------
Bus 1990 7,808,658
Bus 1991 5,474,809
Bus 1992 54,839,221
Bus 1993 54,680,000
Bus 1994 15,000,000
Bus 1995 17,899,668
This was way too long for a comment. After unwinding this query, it appears that you are simply trying to get a count of 'Bus' vehicles by model year (with ALL vehicles in the VEHICLE table are being labeled 'Bus'). If that's the case, you can simplify your query a lot.
SELECT VEH_TYPE
, theYear AS YEAR_MODEL
, COUNT(*) AS TOTAL
FROM (
SELECT 'BUS' AS VEH_TYPE
, SUBSTR(V.YEAR_Val,1,4) AS theYear
FROM VEHICLE V
INNER JOIN CATEGORY c ON v.CATEGORY_CD = c.CATEGORY_CD
AND C.TYPE_CODE='01'
INNER JOIN MAKE mm ON c.MAKE_MO = mm.MAKE_MO
AND MM.VEH_CODE='B'
WHERE V.p_MONTH BETWEEN '199001' AND '199501'
) s1
WHERE theYear IN ('1990','1991','1992','1993','1994','1995')
GROUP BY theYear
You may not need the WHERE clause if your vehicle years are only 1990-1995. And your JOINed tables don't appear to be doing anything other than limiting your VEHICLE table if there are no CATEGORY_CD matches in VEHICLE and CATEGORY, and if there are no MAKE_MO matches in MAKE and CATEGORY. If you were filtering for a specific column from CATEGORY or MAKE, or you had orphaned records in VEHICLE, then you'd want to add those JOINs back in. Otherwise, I don't think they're really doing anything.
Note that SUBSTR(V.YEAR_Val,1,4) will exclude any index you have on V.YEAR_Val, and if that's a column you need regularly, or if there are a lot of VEHICLE records, you may need to split that value into its own column.

Divide and sum in SQL

I got this code and in this code I do a sum of the slow and fast driver. My Problem is I must divide this sum with the normal driver. I donĀ“t know how I can do a division in this statement:
Select *
FROM (
Select date as Datetime, tevent.name as Event, level = case
when levelname = 'High' then 'High'
when levelname = 'Normal' then 'Normal'
when shiftname = 'Low' then 'Low'
end, SUM(value) as sum
from tCount inner join tEvent ON tCount.eventid = tevent.id
where Name in ('Drive Fast', 'Drive Slow')
and date > getdate() -1
and tevent.Name in ('E01','E02','E03','E04','E05','E06','E07','E08')
and CalName = 'Drive'
group by tevent.name, date, levelname
) as s
PIVOT
(
SUM(sum)
FOR Event IN (E01,E02,E03,E04,E05,E06,E07,E08)
) as p
order by Datetime, level
And Then I put the same Select statement with the normal driver :
... from tCount inner join tEvent ON tCount.eventid = tevent.id
where Name in ('drive normal') ...
And I would like to make a division like this:
(Sum('drive fast' + 'drive slow')/Sum('drive normal')) * 100
There is a simpler way to include different cases in different sums inside a SQL statement: sum a case, like in the below calculation of percent:
Select ...
, SUM(case Name
when 'drive fast' then Value
when 'drive slow' then value
else 0 end)
/ SUM(case Name
when 'drive normal' then value
else 0 end) * 100 as percentage
from ...
where ...
group by ...;
As I lack data to test this code, I created a query on the CARS table SAS delivers as training material, implementing the same principle.
select Cylinders
, sum(case origin when 'USA' then EngineSize
when 'Asia' then EngineSize
else 0.0 end)
/ sum(case origin when 'Europe' then EngineSize
else 0.0 end)
* 100 as percentage
from sasHelp.cars
where Cylinders in (4, 5, 6, 12)
group by Cylinders