Simple way to check % of total if I add one criteria - sql

I have the following script:
select count (*)
from somewhere
where 1=1
and criteria 1 = 'xxx'
and criteria 2 = 'xx'
and criteria 3 = 'x'
Is there a nice way to calculate the % of the count with the first 2 criterias vs the count with all 3 criterias ?
So far I'm using something that is not very elegant:
Select x.nb / y.nb
from
(select count (*) as nb
from somewhere
where 1=1
and criteria 1 = 'xxx'
and criteria 2 = 'xx'
and criteria 3 = 'x' ) x
JOIN
(select count (*) as nb
from somewhere
where 1=1
and criteria 1 = 'xxx'
and criteria 2 = 'xx' ) y on 1 = 1
Thanks!

You can use avg():
select avg(case when criteria3 = 'x' then 1.0 else 0 end) as ratio
from somewhere
where criteria 1 = 'xxx' and criteria 2 = 'xx' ;
Or more concisely as:
select avg( (criteria3 = 'x')::int ) as ratio
from somewhere
where criteria 1 = 'xxx' and criteria 2 = 'xx' ;

Related

postgreSQL getting column values as new column and adding

I have the following table
ident
name
count
A1
X
1
A1
Y
2
A1
X
6
A2
X
2
A2
Z
3
What i need is a new table which should look like:
ident
X
Y
Z
A1
7
2
0
A2
2
0
3
so it should give me for every distinct id a sum of all the existing names.
But the columns with are build out of the names should be build automaticly.
i have try
SELECT
ident ,
MAX(CASE WHEN (name = 'X') THEN 1 ELSE NULL END) AS X
FROM
mytable
GROUP BY ident
ORDER BY ident
but with this code i have to make the columns and just can set the sum to 0 or 1.
Thx
Use conditional aggregation, which in Postgres looks like this:
select ident,
sum(count) filter (where name = 'X') as x_sum,
sum(count) filter (where name = 'Y') as y_sum,
sum(count) filter (where name = 'Z') as z_sum
from mytable
group by ident;
The FILTER clause is Standard SQL, but Postgres is one of the few databases that actually supports it. You can, of course, do the same thing with CASE expressions, but FILTER gives the optimizer more hints that can help performance (and many people find it cleaner).
you are looking for sum of count:
SELECT
ident ,
SUM(CASE WHEN (name = 'X') THEN count ELSE NULL END) AS X,
SUM(CASE WHEN (name = 'Y') THEN count ELSE NULL END) AS Y,
SUM(CASE WHEN (name = 'Z') THEN count ELSE NULL END) AS Z
FROM
mytable
GROUP BY ident
ORDER BY ident

SQL query help: How to evaluate value/max(value) based on some conditions in same query

Not an expert in SQL. I am using postgres database with EF migration. Stuck with this requirement. Here it goes.
My table is like this:
A B C D
20 1 1 1
59 0 0 1
57 1 1 1
10 1 0 0
30 1 1 1
15 0 0 0
The order of rows is like oldest to latest(top to bottom).
Half query I have from my project is as below:
SELECT dcr."A"
FROM "DCR" dcr
LEFT JOIN "DCM" dcm ON "Id" = dcm."DCRID"
LEFT JOIN "DC" dc ON dc."Id" = dcm."DCID"
WHERE dcr."B" != 0
AND dcr."C" != 0
AND dcr."B" != 0
ORDER BY "UtcDate" desc
limit(1)
This will fetch me the first part value of latest A when it matches condition. But not the Max part and the division part as explained below.
I want to find the result of ((latest A where B = C = D = 1 divided by max of A in its previous rows where B = C = D = 1) - 1) * 100.
I want this to happen in single query and there are multiple groups like this. Lets say the table contains around 60 rows and we can group them based on some other column. Each group should evaluate this above formula.
Expected result for above example should be:
result = ((30 / 57) - 1) * 100 = (0.5263 - 1) * 100 = -47.73
You can use a subquery to get the max. I don't know why you're writing the query in that strange style, but I will keep it:
SELECT dcr."A" / (SELECT MAX("A")
FROM "DCR"
WHERE dcr."B" != 0
AND dcr."C" != 0
AND dcr."D" != 0)) - 1) * 100
FROM "DCR" dcr
LEFT JOIN "DCM" dcm ON "Id" = dcm."DCRID"
LEFT JOIN "DC" dc ON dc."Id" = dcm."DCID"
WHERE dcr."B" != 0
AND dcr."C" != 0
AND dcr."D" != 0
ORDER BY "UtcDate" desc
limit(1)
maybe something like this?
select (t1."A"/max(t2."A"))*100 from
(select row_number() over() as id,*
from t
where t."A"=1 and t."B" =1 and t."C"=1 ) as t1
join
(select row_number() over() as id,*
from t
where t."A"=1 and t."B" =1 and t."C"=1 ) as t2
on t1.id>t2.id
group by t1."A",t1."E"

Display Default Value Decode Oracle SQL

I am attempting to set values to zero if a user does not exist in one of my tables. Currently, I am using decode to count the number of users that meet a certain criteria and then display the result.
SELECT T.D_CODE,
T.C_NO,
SUM(DECODE(t.Value, 'A', 1, 0)) AS FirstValue,
SUM(DECODE(t.Value, 'B', 1, 0)) AS SecondValue,
SUM(DECODE(t.Value, 'C', 1, 0)) AS ThirdValue,
SUM(DECODE(t.Value, 'F', 1, 0)) AS LastValue
FROM Table T,
Table OtherTable S
WHERE T.T_SSN = S.SSN(+)
AND T.D_CODE = 'INF'
GROUP BY t.D_CODE,
T.C_NO;
The issue is that I have a third table (TT) that has additional values in it. If TT has a value that is not present in Table T, then I need to display that record with 0's for all of the Decode values.
Required output would look something like:
D_CODE, C_NO, FirstValue, SecondValue, ThirdValue, LastValue
INF 600 2 0 0 0
INF 501 0 0 1 0
INF 400 0 0 0 0
Where INF 400 does not exist in Table t, only in Table TT
Any suggestions?
Your problem is that you are filtering the users by T.D_CODE = 'INF' which means that any user that does not met that criteria will not come at all in the results. So, for what I understood of your question you need this:
SELECT T.D_CODE,
T.C_NO,
SUM(CASE WHEN T.D_CODE = 'INF' AND t.Value = 'A' THEN 1 ELSE 0 END) AS FirstValue,
SUM(CASE WHEN T.D_CODE = 'INF' AND t.Value = 'B' THEN 1 ELSE 0 END) AS AS SecondValue,
SUM(CASE WHEN T.D_CODE = 'INF' AND t.Value = 'C' THEN 1 ELSE 0 END) AS AS ThirdValue,
SUM(CASE WHEN T.D_CODE = 'INF' AND t.Value = 'D' THEN 1 ELSE 0 END) AS AS LastValue
FROM Table T
LEFT JOIN Table OtherTable S
ON T.T_SSN = S.SSN
LEFT JOIN AnotherTable TT
ON T.T_SSN = TT.SSN
GROUP BY t.D_CODE,
T.C_NO;
Since you didn't provide any more details about your TT table I just guessed the relation between it and the T table.
Side note: Always use the SQL ANSI [LEFT ]JOINs style.
ALSO Note that for your current query and current fetched fields tables S and TT are totally irrelevant, unless you didn't explain it right.

Returning only id's of records that meet criteria

I need to return distinct ID's of records which meet following conditions :
must have records with field reason_of_creation = 1
and must NOT have records with field reason_of_creation = 0 or null
in the same time.
While i was able to do it, i keep wondering is there more elegant (even recommended) way of doing it.
Here is anonymized version of what i have :
select distinct st.some_id from (
select st.some_id, wanted.wanted_count as wanted, unwanted.unwanted_count as unwanted
from some_table st
left join (
select st.some_id, count(st.reason_of_creation) as wanted_count
from some_table st
where st.reason_of_creation=1
group by st.some_id
) wanted on wanted.some_id = st.some_id
left join (
select st.some_id, count(st.reason_of_creation) as unwanted_count
from some_table st
where st.reason_of_creation=0
group by st.some_id
) unwanted on unwanted.some_id = st.some_id
where wanted.wanted_count >0 and (unwanted.unwanted_count = 0 or unwanted.unwanted_count is null)
) st;
Sample data :
some_id reason_of_creation
1 1
1 0
2 1
3 null
4 0
4 1
5 1
desired result would be list of records with some_id = 2, 5
It seems to me your query is overkill,all you need is some post aggregation filtering
SELECT some_id FROM t
GROUP BY some_id
HAVING SUM(CASE WHEN reason_of_creation = 1 THEN 1 ELSE 0 END)>0
AND SUM(CASE WHEN reason_of_creation = 0 OR reason_of_creation IS NULL THEN 1 ELSE 0 END)=0
I think that more elegant query exists and it is based on assumption what reasoson_of_crdeation field is integer, so minimal possible it's value, which greater than 0 is 1
This is for possible negative values for reasoson_of_crdeation:
select someid from st
where reasoson_of_crdeation != -1
group by someid
having(min(nvl(abs(reasoson_of_crdeation), 0)) = 1)
or
select someid from st
group by someid
having(min(nvl(abs(case when reasoson_of_crdeation = -1 then -2 else reasoson_of_crdeation end), 0)) = 1)
And this one in a case if reasoson_of_crdeation is non-negative integer:
select someid from st
group by someid
having(min(nvl(reasoson_of_crdeation, 0)) = 1)

Join Two Select Statements With Different Columns And Condition

I'm not good at asking question, so i'll give an example of what i want to have.
if i = 1 and xi = 0 then
select a,b,c,d,e,f,g where z = 1
elseif i=0 and xi = 1 then
select a,c,f,h,l,n where w = var
elseif i=1 and xi=1 then
select a,b,c,d,e,f,g, where z = 1
union all
select a,c,f,h,l,n where w = var
end if
How can I join the 2 select statement if their columns are not equal and they both have a unique condition?
Based on the conditions you can create derived tables to fetch desired columns and then to get a union of the two tables add null values in column list of derived tables which have less number of columns:
Pseudo code:
select * from
(select a,b,c,d,e,f,g
where z = 1
and 1 = case when i = 1 and xi = 0 then 1
when i = 1 and xi = 1 then 1
else 0
end) as T1
union all
(select a,c,f,h,l,n ,null -- add null value to equate number of columns
where w = var
and 1 = case when i=0 and xi = 1 then 1
when i=1 and xi = 1 then 1
else 0
end) as T2
Hope this helps!!!
If it is not a requirement not to use dynamic sql I will opt for that one.
Another idea will be to use user defined function returnin tables.
So you encapsulate there the logic...