How to do an average of computed column - sql

I have data in a table called transaction, I have derived purchase value i.e final_rat1 * quantity and sum of purchase quantity
Buysell Quantity Final_rat1
B 50 88.14
B 230 88.14
B 75 88.14
B 87 88.14
B 187 88.14
B 150 88.14
B 221 88.14
Below is the code for it, but when I am averaging purchase value / sum of purchase quantity I'm unable to get proper average. Could you please guide me on this. Below is the code, which I have mentioned
sum(case
when sauda.buysell = 'B' then
sauda.quantity * 1
else
0
end) as "P.Qty",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)
else
0
end) As "P.value",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)/sauda.quantity
else
0
end) as "P.Avg"
Actual Average should be 88.14 where as i m getting an average of 616.98 and if i remove the sum from below average query
case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)/sauda.quantity
else
0
end as "P.Avg"
it says "not a group by function"

Perhaps you mean something like this:
sum(case
when sauda.buysell = 'B' then
sauda.quantity * 1
else
0
end) as "P.Qty",
sum(case
when sauda.buysell = 'B' then
sauda.quantity * (sauda.final_rat1 + sauda.brokpercontract)
else
0
end) As "P.value",
avg(case
when sauda.buysell = 'B' then
sauda.final_rat1 + sauda.brokpercontract
else
0
end) as "P.Avg"

Related

Adding a dummy identifier to data that varies by position and value

I am working on a project in SQL Server with diagnosis codes and a patient can have up to 4 codes but not necessarily more than 1 and a patient cannot repeat a code more than once. However, codes can occur in any order. My goal is to be able to count how many times a Diagnosis code appears in total, as well as how often it appears in a set position.
My data currently resembles the following:
PtKey
Order #
Order Date
Diagnosis1
Diagnosis2
Diagnosis3
Diagnosis 4
345
1527
7/12/20
J44.9
R26.2
NULL
NULL
367
1679
7/12/20
R26.2
H27.2
G47.34
NULL
325
1700
7/12/20
G47.34
NULL
NULL
NULL
327
1710
7/12/20
I26.2
J44.9
G47.34
NULL
I would think the best approach would be to create a dummy column here that would match up the diagnosis by position. For example, Diagnosis 1 with A, and Diagnosis 2 with B, etc.
My current plan is to rollup the diagnosis using an unpivot:
UNPIVOT ( Diag for ColumnALL IN (Diagnosis1, Diagnosis2, Diagnosis3, Diagnosis4)) as unpvt
However, this still doesn’t provide a way to count the diagnoses by position on a sales order.
I want it to look like this:
Diagnosis
Total Count
Diag1 Count
Diag2 Count
Diag3 Count
Diag4 Count
J44.9
2
1
1
0
0
R26.2
1
1
0
0
0
H27.2
1
0
1
0
0
I26.2
1
1
0
0
0
G47.34
3
1
0
2
0
You can unpivot using apply and aggregate:
select v.diagnosis, count(*) as cnt,
sum(case when pos = 1 then 1 else 0 end) as pos_1,
sum(case when pos = 2 then 1 else 0 end) as pos_2,
sum(case when pos = 3 then 1 else 0 end) as pos_3,
sum(case when pos = 4 then 1 else 0 end) as pos_4
from data d cross apply
(values (diagnosis1, 1),
(diagnosis2, 2),
(diagnosis3, 3),
(diagnosis4, 4)
) v(diagnosis, pos)
where diagnosis is not null;
Another way is to use UNPIVOT to transform the columns into groupable entities:
SELECT Diagnosis, [Total Count] = COUNT(*),
[Diag1 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis1' THEN 1 ELSE 0 END),
[Diag2 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis2' THEN 1 ELSE 0 END),
[Diag3 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis3' THEN 1 ELSE 0 END),
[Diag4 Count] = SUM(CASE WHEN DiagGroup = N'Diagnosis4' THEN 1 ELSE 0 END)
FROM
(
SELECT * FROM #x UNPIVOT (Diagnosis FOR DiagGroup IN
([Diagnosis1],[Diagnosis2],[Diagnosis3],[Diagnosis4])) up
) AS x GROUP BY Diagnosis;
Example db<>fiddle
You can also manually unpivot via UNION before doing the conditional aggregation:
SELECT Diagnosis, COUNT(*) As Total Count
, SUM(CASE WHEN Position = 1 THEN 1 ELSE 0 END) As [Diag1 Count]
, SUM(CASE WHEN Position = 2 THEN 1 ELSE 0 END) As [Diag2 Count]
, SUM(CASE WHEN Position = 3 THEN 1 ELSE 0 END) As [Diag3 Count]
, SUM(CASE WHEN Position = 4 THEN 1 ELSE 0 END) As [Diag4 Count]
FROM
(
SELECT PtKey, Diagnosis1 As Diagnosis, 1 As Position
FROM [MyTable]
UNION ALL
SELECT PtKey, Diagnosis2 As Diagnosis, 2 As Position
FROM [MyTable]
WHERE Diagnosis2 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis3 As Diagnosis, 3 As Position
FROM [MyTable]
WHERE Diagnosis3 IS NOT NULL
UNION ALL
SELECT PtKey, Diagnosis4 As Diagnosis, 4 As Position
FROM [MyTable]
WHERE Diagnosis4 IS NOT NULL
) d
GROUP BY Diagnosis
Borrowing Aaron's fiddle, to avoid needing to rebuild the schema from scratch, and we get this:
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=d1f7f525e175f0f066dd1749c49cc46d

Counting columns with a where clause

Is there a way to count a number of columns which has a particular value for each rows in Hive.
I have data which looks like in input and I want to count how many columns have value 'a' and how many column have value 'b' and get the output like in 'Output'.
Is there a way to accomplish this with Hive query?
One method in Hive is:
select ( (case when cl_1 = 'a' then 1 else 0 end) +
(case when cl_2 = 'a' then 1 else 0 end) +
(case when cl_3 = 'a' then 1 else 0 end) +
(case when cl_4 = 'a' then 1 else 0 end) +
(case when cl_5 = 'a' then 1 else 0 end)
) as count_a,
( (case when cl_1 = 'b' then 1 else 0 end) +
(case when cl_2 = 'b' then 1 else 0 end) +
(case when cl_3 = 'b' then 1 else 0 end) +
(case when cl_4 = 'b' then 1 else 0 end) +
(case when cl_5 = 'b' then 1 else 0 end)
) as count_b
from t;
To get the total count, I would suggest using a subquery and adding count_a and count_b.
Use lateral view with explode on the data and do the aggregations on it.
select id
,sum(cast(col='a' as int)) as cnt_a
,sum(cast(col='b' as int)) as cnt_b
,sum(cast(col in ('a','b') as int)) as cnt_total
from tbl
lateral view explode(array(ci_1,ci_2,ci_3,ci_4,ci_5)) tbl as col
group by id

how to sum count sql

How to total count?
SELECT
COUNT(CASE WHEN SHP.id = 1 then 1 ELSE NULL END) as "New",
COUNT(CASE WHEN SHP.id = 2 then 5 ELSE NULL END) as "Accepted"
from SHP
RESULT:
NEW Accepted
1 5
But I need a total count
result: 6
I'd do something like this;
SELECT
COUNT(CASE WHEN id = 1 THEN 1 END) as New,
COUNT(CASE WHEN id = 2 THEN 5 END) as Accepted,
COUNT(CASE WHEN id = 1 THEN 1
WHEN id = 2 THEN 5 END) as Total
FROM SHP
This is exactly what the CASE statement should be used for, the logic is very simple. This will avoid having to perform multiple calculations on the same fields.
As a note, the value in your THEN statement isn't used in this instance at all, it's just doing a COUNT of the number rather than performing a SUM. I've also removed the ELSE NULL because this is what the CASE will do by default anyway.
If your intention was to SUM the values then do this;
SELECT
SUM(CASE WHEN id = 1 THEN 1 END) as New,
SUM(CASE WHEN id = 2 THEN 5 END) as Accepted,
SUM(CASE WHEN id = 1 THEN 1
WHEN id = 2 THEN 5 END) as Total
FROM SHP
Example
Assuming you have only two values in your database, 1 and 2, we can create test data like this;
CREATE TABLE #SHP (id int)
INSERT INTO #SHP (id)
VALUES (1),(2)
And use this query;
SELECT
SUM(CASE WHEN id = 1 then 1 END) as New,
SUM(CASE WHEN id = 2 then 5 END) as Accepted,
SUM(CASE WHEN id = 1 THEN 1
WHEN id = 2 THEN 5 END) as Total
FROM #SHP
Gives this result;
New Accepted Total
1 5 6
Try this:
SELECT
COUNT(CASE WHEN SHP.id = 1 then 1 ELSE NULL END) +
COUNT(CASE WHEN SHP.id = 2 then 5 ELSE NULL END) as "Total"
from SHP
You could wrap your query into a subquery and do something like this:
SELECT SUM(New) as New, Sum(Accepted) as Accepted, Sum(New + Accepted) as Total FROM
(SELECT
COUNT(CASE WHEN SHP.id = 1 then 1 ELSE NULL END) as "New",
COUNT(CASE WHEN SHP.id = 2 then 5 ELSE NULL END) as "Accepted"
from SHP) as SubQuery
That's if you don't want to duplicate doing the counts and just adding the two together.
try this
with s1 as(
SELECT
COUNT(CASE WHEN SHP.id = 1 then 1 ELSE 0 END) as "New"
from SHP
),s2 as
(
SELECT
COUNT(CASE WHEN SHP.id = 2 then 5 ELSE 0 END) as "Accepted"
from SHP
)
select sum("New"+ "Accepted") from s1,s2

sql subquery that collects from 3 rows

I have a huge database with over 4 million rows that look like that:
Customer ID Shop
1 Asda
1 Sainsbury
1 Tesco
2 TEsco
2 Tesco
I need to count customers that within last 4 weeks had shopped in all 3 shops Tesco Sainsbury and Asda. Can you please advice if its possible to do it with subqueries?
This is an example of a "set-within-sets" subquery. You can solve it with aggregation:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
This structure is quite flexible. So if you wanted Asda and Tesco but not Sainsbury, then you would do:
select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) = 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0;
EDIT:
If you want a count, then use this as a subquery and count the results:
select count(*)
from (select customer_id
from Yourtable t
where <shopping date within last four weeks>
group by customer_id
having sum(case when shop = 'Asda' then 1 else 0 end) > 0 and
sum(case when shop = 'Sainsbury' then 1 else 0 end) > 0 and
sum(case when shop = 'Tesco' then 1 else 0 end) > 0
) t

Oracle SQL dividing two self defined columns

if i have the following select two count cases:
COUNT(CASE WHEN STATUS ='Færdig' THEN 1 END) as completed_callbacks,
COUNT(CASE WHEN SOLVED_SECONDS /60 /60 <= 2 THEN 1 END) as completed_within_2hours
and i want to devide the two results with eachother how can i achieve this?
this is my attemt however that failed:
CASE(completed_callbacks / completed_within_2hours * 100) as Percentage
i know this is a rather simple question but i havnt been able to find the answer anywhere
You have to create a derived table:
SELECT completed_callbacks / completed_within_2hours * 100
FROM (SELECT Count(CASE
WHEN status = 'Færdig' THEN 1
END) AS completed_callbacks,
Count(CASE
WHEN solved_seconds / 60 / 60 <= 2 THEN 1
END) AS completed_within_2hours
FROM yourtable
WHERE ...)
Try this:
with x as (
select 'Y' as completed, 'Y' as completed_fast from dual
union all
select 'Y' as completed, 'N' as completed_fast from dual
union all
select 'Y' as completed, 'Y' as completed_fast from dual
union all
select 'N' as completed, 'N' as completed_fast from dual
)
select
sum(case when completed='Y' then 1 else 0 end) as count_completed,
sum(case when completed='N' then 1 else 0 end) as count_not_completed,
sum(case when completed='Y' and completed_fast='Y' then 1 else 0 end) as count_completed_fast,
case when (sum(case when completed='Y' then 1 else 0 end) = 0) then 0 else
((sum(case when completed='Y' and completed_fast='Y' then 1 else 0 end) / sum(case when completed='Y' then 1 else 0 end))*100)
end pct_completed_fast
from x;
Results:
"COUNT_COMPLETED" "COUNT_NOT_COMPLETED" "COUNT_COMPLETED_FAST" "PCT_COMPLETED_FAST"
3 1 2 66.66666666666666666666666666666666666667
The trick is to use SUM rather than COUNT, along with a decode or CASE.
select
COUNT(CASE WHEN STATUS ='Færdig' THEN 1 END)
/
COUNT(CASE WHEN SOLVED_SECONDS /60 /60 <= 2 THEN 1 END)
* 100
as
Percentage