pgsql rotate table and generate dynamic columns based on values - sql

I want to make a dynamic pivot on pgsql table
Original table :
time
strategy
pnl
1
a
100
2
a
200
3
a
300
1
b
1000
2
b
2000
1
c
22
target table :
time
sum
a
b
c
1
1132
100
1000
32
2
2200
200
2000
0
3
22
0
0
22
the problem that the strategy content is dynamic i can have sometimes over 40 unique values (in this example there are only 3 a,b,c )
i have the following code it looks like a good start but the are some problems i cannot solve
SELECT time,
--sum(case when strategy='a' then pnl else 0 end) AS "a" ,
--sum(case when strategy='b' then pnl else 0 end) AS "b" ,
--sum(case when strategy='c' then pnl else 0 end) AS "c"
--generate the contect above, (when using the code above the function works)
(SELECT string_agg(clause, ',')
FROM (SELECT format('sum(case when strategy=''%s'' then pnl else 0 end) AS "%s" ',
strategy, strategy) AS clause
FROM (SELECT DISTINCT strategy FROM server_logs.logs where strategy != '' and subclass = 'pnl') s
ORDER BY strategy) clauses)
FROM (
select case when strategy is null then 'system' else strategy end as strategy,
time,
sum(case when value::float!=0 then 0::float else value::float end) as pnl
FROM server_logs.logs
where subclass='pnl'
group by rollup(strategy), time
) as t
group by time
order by time desc
;

Related

Show two different sum columns based on a single column

Show two different sum columns based on another column.
For this table:
ID Item Quantity Location
1 1 10 A
2 1 10 B
3 1 10 A
4 2 10 A
5 2 10 A
6 2 10 B
7 3 10 A
8 3 20 A
I need to see the total quantities for both location A and location B (to compare which is higher), but only for items that have a location B:
Expected result:
Item Quantity A Quantity B
1 20 10
2 20 10
I've been trying this but getting errors:
SELECT st.item, st.qty ALIAS(stqty),
(SELECT SUM(dc.qty)
FROM table dc
WHERE st.item = dc.item) ALIAS(dcqty))
FROM table st
WHERE location ='b'
I can do this easily with two queries obviously, but I was hoping for a way to do it in one.
you can use a sum with case statement to do your pivot then a having to exclude rows with no total for b
here is the fiddle
https://www.db-fiddle.com/f/rS8fgvWoFxn879Utc2CKbu/0
select Item,
sum(case when Location = 'A' then Quantity else 0 end),
sum(case when Location = 'B' then Quantity else 0 end)
from myTable
group by Item
having sum(case when Location = 'B' then Quantity else 0 end) > 0

SQL: create another column that calculates ratio

So I have a table that looks like the following:
car owner
non car owner
have dog
num ppl
1
0
1
60
0
1
1
80
1
0
0
90
1
0
0
98
I am trying to add another column to find the ratios. For example, the total number of car owners is 110. If I want to find the ratio of people who own car and have dog, then I have to divide 60/110 for the first row. Also, the total number of non car owners is 98. Therefore, if I want to find that ration, I need to divide 80 by 98 for the second row and so on.
So far, I have tried the following code:
with a as (
select
id,
case when car_owner = 1 then 1 else 0 end car_owner,
case when non_car_owner = 1 then 1 else 0 end as non_car_owner = 1
from `xyz_table`
),
b as (select
car_owner,
non_car_owner,
case when have_dog = 1 then 1 else 0 end have_dog,
count(distinct id) num_ppl
from `xyz_table`
join a using (id)
group by 1,2,3
order by 4 desc
)
select *, num_ppl/(select (case when dog_owner = 1 then 110 else 0 end) as ratio
from a)
from b
Unfortunately , it throws the following error:
Scalar subquery produced more than one element
Any help would be appreciated.
PS. I am running this code on google bigquery.
If I want to find the ratio of people who own car and have dog,
You can use avg():
select avg(car_owner * have_dog)
from t;

SQL - Impala - How to unfold one categorical column into many?

I have the following table :
user category number
1 A 8
1 B 6
2 A 1
2 C 9
3 B 5
I want to "unfold" or "dummify" the category column and fill them with the "number" column to obtain:
user cat_A cat_B cat_C
1 8 6 0
2 1 0 9
3 0 5 0
Is it possible to achieve this in SQL (Impala) ?
I found this question How to create dummy variable columns for thousands of categories in Google BigQuery?
However it seems a little bit complex and I'd rather do it in Pandas.
Is there a simpler solution, knowing that I have 10 categories (A, B, C, D etc)?
You can try to use condition aggregate function.
SELECT user,
SUM(CASE WHEN category = 'A' THEN number ELSE 0 END) cat_A,
SUM(CASE WHEN category = 'B' THEN number ELSE 0 END) cat_B,
SUM(CASE WHEN category = 'C' THEN number ELSE 0 END) cat_C
FROM T
GROUP BY user

SQL table data horizontally using PIVOT

My SQL table is
GUID Step_ID Value
----------------------------------------------
ADFE12-ASDER-... 1 10
ADFE12-ASDER-... 2 20
ADFE12-ASDER-... 3 30
ADFE12-ASDER-... 4 160
CD4563-FG567-... 1 20
CD4563-FG567-... 2 80
Q23RT5-GH678... 1 30
Q23RT5-GH678-... 2 80
Q23RT5-GH678-... 3 20
And Expected result should be
GUID 1 2 3 4
---------------------------------------------------
ADFE12-ASDER-... 10 20 30 160
CD4563-FG567-... 20 80 NULL NULL
Q23RT5-GH678-... 30 80 20 NULL
Here I need to get the details on the basis of column whose data type is GUID. I tried using PIVOT table but getting an exception because I cannot use an aggregate function on GUID column. Is there any other alternative or approach I can use to get the above desired result.
Try this:
select [GUID],[1],[2],[3],[4]
from
(
select [GUID], Step_ID, Value
from test
) d
pivot
(
max(Value)
for Step_ID in ([1],[2],[3],[4])
) piv;
SQL FIDDLE DEMO
You could try manually pivotting, I don't have a SQL Server handy to check the behavior on a GUID but this has worked well for me in the past.
select guid,
max(case when step_ID = 1 then value else null end) step_1,
max(case when step_ID = 2 then value else null end) step_2,
max(case when step_ID = 3 then value else null end) step_3,
max(case when step_ID = 4 then value else null end) step_4
from your_table
group by guid;
HTH

return value when count equals variable in sql server

I have a table to update with other table data. For this I created a trigger. Inside trigger, I must check how many active occurrences of each id. If this number of occurrences is same number than a variable value then return 1 (true) otherwise 0 (false).
I get the variable
DECLARE #num_gerencias numeric(2, 0)
SELECT #num_gerencias = (SELECT COUNT(id_gerencia) FROM FR_GERENCIES)
select #num_gerencias
This works ok... returns 5
Then, I make a count of occurrences of the l_activo variable in other table (variable is a bit):
SELECT id_operacio, SUM(CASE WHEN l_activo = 1 THEN 1 ELSE 0 END)
FROM FR_GERENCIES_OPERACIONS o
GROUP BY o.id_operacio
This query also works nice, returns:
2958 5
2959 0
2960 5
2961 3
2962 5
2963 5
2964 2
2965 4
2966 5
2967 5
All perfect... now i must get same list, but if sum equals to #num_gerencias, then put 1 and 0 otherwise.
Expected result table
2958 1
2959 0
2960 1
2961 0
2962 1
2963 1
2964 0
2965 0
2966 1
2967 1
I've tried with CASE
SELECT DISTINCT id_operacio, CASE WHEN
(
SELECT SUM(CASE WHEN l_activo = 1 THEN 1 ELSE 0 END)
FROM FR_GERENCIES_OPERACIONS o
GROUP BY o.id_operacio
) = #num_gerencias THEN 1 ELSE 0 END
but I'm getting error:
Mens . 512 , Level 16 , State 1, Line 6
The subquery returned more than one value , which is not correct when it goes below = , ! = , <, < = ,>, > = Or when used as an expression .
I also tried with an IF (i guess this option is totally wrong for this case... but I've tried)
SELECT DISTINCT id_operacio,
IF #num_gerencias = (SELECT SUM(CASE WHEN l_activo = 1 THEN 1 ELSE 0 END)
FROM FR_GERENCIES_OPERACIONS o
GROUP BY o.id_operacio)
1
ELSE 0
FROM FR_GERENCIES_OPERACIONS
But I have syntax errors...
Any idea how can i reach expected result table?
You were nearly there, however your grouping and selection must occur outside of your case statement:
SELECT DISTINCT
id_operacio
,CASE
WHEN SUM(CAST(l_activo AS INTEGER)) = #num_gerencias THEN 1
ELSE 0
END
FROM FR_GERENCIES_OPERACIONS o
GROUP BY o.id_operacio