Below is my SQL query
select
case when x < 2 then a
when x = 0 then Max(a) end a
,case when x < 2 then b
when x = 0 then Sum(b) end b
from T
How can we do this? I am using right now Union to get the required result. Looking for a better way to do this.
You can get these aggregate values into a variable and use it.
DECLARE #maxA int;
DECLARE #sumB int;
SELECT #maxA = max(a),#sumB = sum(b) FROM t;
SELECT CASE
WHEN x < 2 THEN a
WHEN x = 0 THEN #maxA
END a ,
CASE
WHEN x < 2 THEN b
WHEN x = 0 THEN #sumB
END b
FROM T
You can use CASE When conditions inside the Aggregate functions.
i.e.
SELECT SUM(CASE WHEN x < 2 THEN a WHEN x = 0 THEN #maxA END) AS sum_a
Related
This is a simple example of the problem:
SELECT CASE WHEN a = 5 THEN 0 ELSE 1 END AS x
FROM table
WHERE x = 0;
I will get an error message that x is not amongst the possible column names.
Could anyone advise me how to solve this?
SELECT
CASE WHEN a = 5 THEN 0
ELSE 1
END AS x FROM table
WHERE
CASE WHEN a = 5 THEN 0
ELSE 1
END=0
Let's say I have 5 columns, which could all contain the same value. I want to calculate a new column that tells me whether a specific value occurs more than once. Example of desired outputs with different situations:
I want to scan all rows that contains at least one of value 'X':
id
A
B
C
D
E
Result
1
X
Y
X
Z
True
2
X
Y
Y
Z
False
3
Y
Y
Z
False
4
X
X
Y
X
True
A 'case when' would in theory be possible, but going through all the options is not doable: this requires too many combinations. Maybe some inner query?
Edit:
I actually found a solution, by making a join. But the answer of Gordon Linoff is much more clean.
select id,
case when b.num_X > 1 then True else False end as result
from foo f
join (
select a+b+c+d+e as num_X from (
select
id,
case when A = 'X' then 1 else 0
end as a,
case when B = 'X' then 1 else 0
end as b,
case when C = 'X' then 1 else 0
end as c,
case when D = 'X' then 1 else 0
end as d,
case when E = 'X' then 1 else 0
end as e
from foo
)
) b on f.id = b.id
One method is to just count them:
select t.*,
( (a = 'X')::int + (b = 'X')::int + (c = 'X')::int + (d = 'X')::int + (e = 'X')::int) ) >= 2 as result
from t;
If the columns can contain NULL values, then you need to pay attention to that. One method is to use coalesce() in the above expression:
( (coalesce(a, '') = 'X')::int +
(coalesce(b, '') = 'X')::int +
(coalesce(c, '') = 'X')::int +
(coalesce(d, '') = 'X')::int +
(coalesce(e, '') = 'X')::int)
) >= 2 as result
Say, I have a table holding integer values from 0 up to 9,999 and I want to make a distribution plot of the population of values in each percentile.
Below is what comes to mind. Is there a better way?
CREATE TABLE A(x INTEGER);
SELECT
(SELECT COUNT(*) FROM A WHERE x>=0 AND x<10) AS prcntl_01,
(SELECT COUNT(*) FROM A WHERE x>=10 AND x<20) AS prcntl_02,
(SELECT COUNT(*) FROM A WHERE x>=20 AND x<30) AS prcntl_03,
(SELECT COUNT(*) FROM A WHERE x>=30 AND x<40) AS prcntl_04,
(SELECT COUNT(*) FROM A WHERE x>=40 AND x<50) AS prcntl_05,
...
(SELECT COUNT(*) FROM A WHERE x>=990 AND x<1000) AS prcntl_100,
The size of the SQL statement is not a consideration as I can generate it on the fly. I am just wondering if there is an idiomatic way to get population counts in each percentile.
Use conditional aggregation instead of multiple queries:
SELECT sum(case when x >= 0 AND x < 10 then 1 else 0 end) as prcntl_01,
sum(case when x >= 10 AND x < 20 then 1 else 0 end) as prcntl_02,
. . .
sum(case when x >= 990 AND x < 1000 then 1 else 0 end) as prcntl_100
FROM A;
If you want the values in separate rows rather than columns, you can simply do:
select n as which,
sum(case when x >= (n - 1)*10 and x < n*10 - 1 then 1 else 0 end) as percentile
from A cross join
generate_series(1, 100) as n
group by n;
This limits the amount of code you have to write.
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...
How does one turn these multiple rows into one row? N and Y are bool values.
Id IsPnt IsPms, IsPdt
1 N Y N
1 N Y N
1 Y N N
into this
Id IsPnt IsPms, IsPdt
1 Y Y N
Edit:
The query that produces the resultset looks like this
select b.id,
CASE mpft.PlanIndCd WHEN 'PBMN' THEN 1 ELSE 0 END AS IsPnt,
CASE mpft.PlanIndCd WHEN 'PBMT' THEN 1 ELSE 0 END AS IsPbt,
CASE mpft.PlanIndCd WHEN 'PBMS' THEN 1 ELSE 0 END AS IsPms
from vw_D_SomveViewName pb
-- bunch of joins
where mpft.PlanIndCd in ('HANR', 'PBMN','PBMT','PBMS','HAWR')
You can simply use MAX() on this if the values are really Y and N only.
SELECT ID, MAX(IsPnt) IsPnt, MAX(IsPms) IsPms, MAX(IsPdt) IsPdt
FROM tableName
GROUP BY ID
UPDATE 1
SELECT b.id,
MAX(CASE mpft.PlanIndCd WHEN 'PBMN' THEN 1 ELSE 0 END) AS IsPnt,
MAX(CASE mpft.PlanIndCd WHEN 'PBMT' THEN 1 ELSE 0 END) AS IsPbt,
MAX(CASE mpft.PlanIndCd WHEN 'PBMS' THEN 1 ELSE 0 END) AS IsPms
FROM vw_D_SomveViewName pb
-- bunch of joins
WHERE mpft.PlanIndCd in ('HANR', 'PBMN','PBMT','PBMS','HAWR')
GROUP BY b.ID
Will this work?
select
id,
max(IsPnt),
max(IsPms),
max(IsPdt)
from
table
GROUP BY
id
After the edit of your question, you can simply use the PIVOT table operator directly instead of using the MAX expression, something like:
SELECT
Id,
PBMN AS IsPnt,
PBMT AS IsPbt,
PBMS AS IsPms
FROM
(
SELECT
id,
mpft.PlanIndCd,
ROW_NUMBER() OVER(PARTITION BY id
ORDER BY ( SELECT 1)) AS RN
from vw_D_SomveViewName pb
-- bunch of joins
where mpft.PlanIndCd in ('HANR', 'PBMN','PBMT','PBMS','HAWR')
) AS t
PIVOt
(
MAX(RN)
FOR PlanIndCd IN ([PBMN], [PBMT], [PBMS])
) AS p;
You can see it in action in the following demo example:
Demo on SQL Fiddle
select Id, MAX(IPnt), MAX(IsPms), MAX(IsPdt)
from table etc