How to pivot a table in sql and sum the amounts? - sql

I have a table called test_table. This table looks like below
id
type
value
1
tax
10
1
premium
21
1
tax
3
1
correction
4.5
2
premium
15
I would like to "pivot" this table and make it look like below
id
premium
tax
correction
1
21
13 (=10+3)
4.5
2
15
NULL
NULL
create columns by type (premium, tax and correction)
sum the amounts by type and by id
With my basic sql knowledge, I have no idea how to build this query. Can you help me with this?

You may try the following pivot query:
SELECT
id,
SUM(CASE WHEN type = 'premium' THEN value ELSE 0 END) AS premium,
SUM(CASE WHEN type = 'tax' THEN value ELSE 0 END) AS tax
SUM(CASE WHEN type = 'correction' THEN value ELSE 0 END) AS correction
FROM yourTable
GROUP BY id
ORDER BY id;
Note that the above will report zero for those cells having entry in the source table.

In MS Sql Server, the PIVOT syntax should be sufficiant for this.
select *
from (
select id, [type], value
from test_table
) src
pivot (
sum(value)
for [type] in ([premium], [tax], [correction])
) pvt
order by id

Related

Is there a way to collect the data and inspect in one pass using groupby function

Sample Data of table_1
Have this Query that returns
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0 END) AS num_activity_a_or_b
from table_1
group by customer
Results:
Want to extend this to return one more column if for a given code say X1 if the Activity is "a" and "c" then return num_of_a_and_c_activity.
A bit stuck how to collect and inpect the code and activities in one pass.
can we combine windowing function to achieve this.
Please advise and help
UPDATE:
based on the updated results, maybe the below query is what you need
So what i assume is that you need both a and c as well x1 .
So I count distinct activities which are a and c and then do integer division by 2. if only a is present then count distinct =1 but 1/2 =0 in integer division.
It is only 1 when both a and c are present.
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0
END) AS num_activity_a_or_b,
COUNT(DISTINCT CASE WHEN code IN ('x1') AND activity IN ( 'a','c')
THEN activity
ELSE NULL
END)/2 AS num_activity_a_and_c
from table_1
group by customer
Maybe your query can be
select
customer,
SUM(CASE WHEN activity IN ( 'a','b')
THEN 1
ELSE 0
END) AS num_activity_a_or_b,
SUM(CASE WHEN code IN ('x1') AND activity IN ( 'a','c')
THEN 1
ELSE 0
END) AS num_activity_a_or_c
from table_1
group by customer

How to group and get count of rows based on value of one column in sql server

I have a table of requests with columns RequestType,status .Status column values can be in-progress,complated etc.
I would like to get the list like
RequestType In-Progress Completed Total
Type1 10 5 15
Type2 10 10 20
I tried with group by using the 2 columns( RequestType,status) ,but it does not give me the exact result.
Please help me with the sql query.
Thanks in advance
Subin
One way to do it is using conditional aggrigation:
SELECT RequestType,
SUM(CASE WHEN Status = 'In-Progress' THEN 1 ELSE 0 END) As 'In-Progress',
SUM(CASE WHEN Status = 'Completed' THEN 1 ELSE 0 END) As 'Completed',
COUNT(Status) As 'Total'
FROM TableName
WHERE Status IN('In-Progress', 'Completed')
GROUP BY RequestType
Use PIVOT
select *, [In-Progress]+[Completed] total
from TableName
pivot ( count(status) for status in ([In-Progress], [Completed])) as p

SQL query - db2/400 iseries

My SQL group statement results in the below table. From this table, I need to subtract Qty with Code ='S' from Qty with code ='B' when Price and Date are matching.
For example, in the below table I need the value to be stored in a work variable.
1) 100-50 = 50 for the first 2 rows
2) 60 -30 = 30 for the 3rd and 4 th row
3) The last row since it does not have code 'S' it should return just 20
Table
Price Date Code Sum(Qty)
9.0 201512 B 100
9.0 201512 S 50
8.0 201506 B 60
6.0 201506 S 30
5.0 201508 B 20
SQL query used to get the above table
select Price, Date, Code,sum(Qty) from Table
where Type = 'A' and Acct = 'CLOSED'
group by Price,Date,Code
order by Price,Date
Can I modify my existing SQL statement typed above using CASE statements to get my required output. I tried it but Cursor returns one by one row and CASE does not seem to work
exec sql
declare c1 cursor for
select Price, Date, Code,
Case when Code ='B' then ifnull(sum(Qty),0)
when Code ='S' then (-1 * ifnull(sum(Qty),0)) end
from Table
where Type = 'A' and Acct = 'CLOSED'
group by Price,Date,Code
order by Price,Date
exec sql
open c1
exec sql
fetch c1 into :var_price, :var_date, :var_code, :var_Bqty, :VarSqty
Using SQLRPGLE on iseries system.
You can use conditional aggregation for this:
select Price, Date,
sum(case when code = 'B' then Qty when code = 'S' then -QTY end) as diff
from Table
where Type = 'A' and Acct = 'CLOSED'
group by Price, Date
order by Price, Date;

SQL Server Completion Percentage Category

im a bit new to sql server, so hopefully this isnt something too convoluted. if i have a table with a bunch of data that shows different records that have been complete or not...
TABLE 1
ID CATEGORY COMPLETE
1 reports yes
2 reports no
3 processes no
4 processes yes
5 reports no
6 events yes
...what would be the best way of creating a new field that would show the percentage complete for every category?
TABLE 2
ID CATEGORY PERCENTAGE
1 events 100%
2 processes 50%
3 reports 33%
any help would be greatly appreciated, thank you.
group by category column and use conditional sum to get only complete = 'yes' cases in the numerator.
select category,
100 * 1.0 * sum(case when complete = 'yes' then 1 else 0 end)/count(*) as pct
from tablename
group by category
You can use windowed functions and PARTITION BY Category:
SELECT DISTINCT Category,
[percentage] = ROUND(100 * SUM(CASE complete WHEN 'yes' THEN 1.0 ELSE 0.0 END)
OVER (PARTITION BY Category)/
COUNT(*) OVER (PARTITION BY Category),0)
FROM #tab;
LiveDemo
With insert to second table:
SELECT DISTINCT
[id] = IDENTITY(INT, 1,1)
,category
,[percentage] = ROUND(100 * SUM(CASE complete WHEN 'yes' THEN 1.0 ELSE 0.0 END)
OVER (PARTITION BY CATEGORY)/
COUNT(*) OVER (PARTITION BY Category),0)
INTO #table2
FROM #tab
ORDER BY [percentage] DESC;
SELECT *
FROM #table2;
LiveDemo2
I think the simplest approach is to use avg():
select category,
avg(case when complete = 'yes' then 100.0 else 0 end) as pct
from tablename
group by category;
If you want this as a number with a percentage, you need a bit more string manipulation:
select category,
str(avg(case when complete = 'yes' then 100.0 else 0 end)) + '%' as pct
from tablename
group by category;
However, I would recommend keeping the value as a number.

Conditional SUM with SELECT statement

I like to sum values in a table based on a condition taken from the same table called. The structure of the table as per below. The table is called Data
Data
Type Value
1 5
1 10
1 15
1 25
1 15
1 20
1 5
2 10
3 5
If the Value of Type 2 is larger than the Value of Type 3 then I like to subtract the Value of Type 2 from the sum of all the Values in the table. I'm not sure how to write the IF statements using Values looked up in the table. I have tried below but it doesn't work.
SELECT SUM(Value)-IF(SELECT Value FROM Data WHERE Type=2>SELECT Value
FROM Data WHERE Type=3 THEN SELECT Value FROM Data
WHERE Type=2 ELSE SELECT Value FROM Data WHERE Type=3) FROM Data
or
SELECT SUM(d.Value)-IIF(a.type2>b.type3, a.type2, b.type3)
FROM Data d, (SELECT Value AS type2 FROM Data WHERE Type=2) a,
(SELECT Value AS type3 FROM Data WHERE Type=3) b
If I follow your logic correctly, then this would seem to do what you want:
select d.value - (case when d2.value > d3.value then d2.value else 0 end)
from data d cross join
(select value from data where type = 2) d2 cross join
(select value from data where type = 3) d3 ;
EDIT:
If you want just one number, then use conditional aggregation:
select sum(value) -
(case when sum(case when type = 2 then value else 0 end) >
sum(case when type = 3 then value else 0 end)
then sum(case when type = 2 then value else 0 end)
else 0
end)
from data;
Thanks for pointing me in the right direction. This is what I came up with in the end. It is a little bit different to the reply above since I'm using MS Access
SELECT SUM(Value)-IIf(SUM(IIf(Type=2, Value, 0)>SUM(IIf(Type=3, Value, 0), SUM(IIf(Type=2, Value, 0), SUM(IIf(Type=3, Value, 0) FROM Data
It is them same as the second suggestion above but adapted to MS Access SQL.