T-SQL: How do I flatten out a table like this? [duplicate] - sql

This question already has answers here:
Convert Rows to columns using 'Pivot' in SQL Server
(9 answers)
Closed 3 years ago.
I have a table I loaded that looks like this:
CUSTID VALUETYPE COST
1 A 123
1 B 456
1 C 789
2 B 222
And I need to flatten it out in the same table or insert into a new one to look like this:
CUSTID A B C
1 123 456 789
2 0 222 0
Each row has an identity column not shown.
What would this cursor look like?
Thank you.

I don't see that you need to sum the columns:
select
custid,
max(case when valuetype = 'A' then cost else 0 end) A,
max(case when valuetype = 'B' then cost else 0 end) B,
max(case when valuetype = 'C' then cost else 0 end) C
from tablename
group by custid

Use a query, such as conditional aggregation:
select custid,
sum(case when valuetype = 'A' then cost end) as a,
sum(case when valuetype = 'B' then cost end) as b,
sum(case when valuetype = 'C' then cost end) as c
from t
group by custid;

use case when
select custid , sum(case when valuetype='A' then cost else 0 end) A,
sum(case when valuetype='B' then cost else 0 end) B
,sum(case when valuetype='C' then cost else 0 end) C
from t group by custid

You could make use of a PIVOT
SELECT
CUSTID
,ISNULL(p.A,0) AS A
,ISNULL(p.B,0) AS B
,ISNULL(p.C,0) AS C
FROM t
PIVOT (
SUM(COST) FOR VALUETYPE IN ([A],[B],[C])) p

If you don't mind NULL values in the Results
Select *
From YourTable
Pivot (sum(Cost) for ValueType in ([A],[B],[C])) pvt
Returns
CUSTID A B C
1 123 456 789
2 NULL 222 NULL
Otherwise, You Can Eliminate NULL Values
Select *
From (Select * From YourTable
Union All
Select A.CustID ,B.VALUETYPE,0
From (Select Distinct CustID from YourTable) A
Cross Join (Select Distinct VALUETYPE from YourTable) B
) src
Pivot (sum(Cost) for ValueType in ([A],[B],[C])) pvt
Returns
CUSTID A B C
1 123 456 789
2 0 222 0

Related

How to sum() if missing data in same column in SQL

I need to sum up the quantity according to typein the table below.
Table
Name Quantity Type
a 6 AB
b 2 BB
b 4 AB
c 8 BB
a 3 BB
b 5 AB
Outcome
Name AB_Type BB_Type
a 6 3
b 9 2
c 0 8
I am trying the below query but I can't get the numbers right.
SELECT S.Name, SUM(S1.Quantity) AS AB_Type, SUM(S2.Quantity) AS BB_Type
FROM Table AS S, Table AS S1, Table AS S2
WHERE S.Name = S1.SName = S2.Name AND S1.Type = 'AB'AND S2.Type = 'BB'
GROUP BY S.Name;
Thanks in advance!!
Try this
SELECT
Name,
SUM(CASE WHEN Type = 'AB' THEN Quantity ELSE 0 END) AS AB_Type,
SUM(CASE WHEN Type = 'BB' THEN Quantity ELSE 0 END) AS BB_Type
FROM Table
GROUP BY Name
you can use pivot as follows:
SELECT Name,
iif(AB_Type is null,0,AB_Type) AB_Type,
iif(BB_Type is null,0,BB_Type) BB_Type
FROM (
SELECT
Name
,Quantity
,CONCAT(Type, '_type') AS Col
FROM table
) Src
PIVOT (
sum(Quantity)
FOR Col IN (
[AB_Type], [BB_Type]
)
) Pvt

Pivot data in SQL (repeated levels)

I have a question regarding pivoting data in SQL.
Input data:
TABLE NAME temp
id cat value
1 A 22
1 B 33
1 C 44
1 C 55
My ideal output would be:
id A B C
1 22 33 44
1 22 33 55
Can someone provide some hints on this?
Thanks!
select * from
(
select
id,cat,value
from tablename
)
as tablo
pivot
(
sum(value)
for cat in ([A],[B],[C])
) as p
order by id
use case when, assuming you did a mistake in output format in 2nd rows
select id, max( case when cat='A' then value end) as A,
max(case when cat='B' then value end) as B,
max(case when cat='C' then value end)as C from table
group by id
You need row_number() function with conditional aggregation :
select id, max(case when cat = 'a' then value end) a,
max(case when cat = 'b' then value end) b,
max(case when cat = 'c' then value end) c
from (select t.*, row_number() over (partition by id, cat order by value) as seq
from table t
) t
group by id, seq;
However, it doesn't produce your actual output (it leaves null value where the cat has only one value compare to other cats) but it will give the idea of how to do that.
Use CASE WHEN and MAX aggregation:
select id, max(case when cat='A' then value end) as A,max(case when cat='B' then value end) as B,
max(case when cat='C' then value end) as C from temp
group by id

SQL Server transform 3 lines with 3 columns in 9 columns one line

I have this query:
SELECT TOP 3
A.Id,
A.NAME as Name,
B.Rate as PayRate,
C.Description as Currency
FROM
TABLEA A
JOIN
TABLEB B ON A.id = B.TableAId
JOIN
TABLEC C ON B.Id = C.TableBId
WHERE
TABLEA.FieldX = 1
AND TABLEB.FieldX = 3
This returns a result something like this:
Id Name PayRate Currency
-------------------------------------
2503 John 110.00 Dollar
2503 Mike 5.00 EURO
2503 Erik 10.00 Dollar
2504 Rob 2.00 EURO
2504 Elis 11.00 Dollar
2505 May 4.00 Dollar
But I would like to return something like that:
Id Name01 PayRate01 Currency01 Name02 PayRate02 Currency02 Name03 PayRate03 Currency03
--------------------------------------------------------------------------------------------------
2503 John 110.00 Dollar Mike 5.00 EURO Erik 10.00 Dollar
2504 Rob 2.00 EURO Elis 11.00 Dollar Null Null Null
2505 May 4.00 Dollar Null Null Null Null Null Null
It is not fixed query, this is just an example is going to bring many records from the same ID. Some could have 1 line, 2 lines, 3 lines or more lines. So ever ID I want to split into 3 groups of columns.
You should be able to use PIVOT to achieve this result. Please see PIVOT Example from documentation. Something like below...
SELECT id, [0] AS Name01, [1] AS Name02, [2] AS Name03
FROM
(SELECT id, name
FROM table) p
PIVOT
(
name
FOR id IN
( [0], [1], [2] )
) AS pvt
ORDER BY pvt.id;
If the data is fixed then one way to do that is to use case statements like below.
Select
id,
max(case when name='John' then payrate else null end) PayRate01,
max(case when name='John' then currency else null end) Currency01,
max(case when name='John' then name else null end) Name01,
max(case when name='Mike' then payrate else null end) PayRate02,
...
...
from table
group by id
You can use conditional aggregation with row_number():
select id,
max(case when seqnum = 1 then name end) as name_1,
max(case when seqnum = 1 then payrate end) as payrate_1,
max(case when seqnum = 1 then currency end) as currency_1,
max(case when seqnum = 2 then name end) as name_2,
max(case when seqnum = 2 then payrate end) as payrate_2,
max(case when seqnum = 2 then currency end) as currency_2,
max(case when seqnum = 3 then name end) as name_3,
max(case when seqnum = 3 then payrate end) as payrate_3,
max(case when seqnum = 3 then currency end) as currency_3
from (select t.*,
row_number() over (partition by id order by id) as seqnum
from t
) t
group by id;

conditional aggregation on two different groups in SQL

Here is my data
COUNTYID POLLUTANT TYPE EMISSION
1 A 1
1 A 2
1 B 1
1 B 2
2 A 1
2 A 2
2 B 1
2 B 2
3 A 1
3 A 2
3 B 1
3 B 2
if I do
SELECT sum(EMISSION) from table where POLLUTANT = 'A' group by COUNTYID;
I would get pollution from Polutant 'A'. how can I write a query to get following data:
column 1 with sum of A, column 2 with sum of B, column 3 with sum of A and B?
Thank you
You can use case for filter the value you need
select COUNTYID, sum(case when POLLUTANT='A'then EMISSION else 0 END) tot_a
, sum(case when POLLUTANT='B'then EMISSION else 0 END) tot_b
, sum(EMISSION) tot_a_b
from my_table
group by COUNTYID
You can use conditional aggregation. This moves the filtering conditions from the where clause to the sum()s:
select countyid,
sum(case when emission = 'A' then emission else 0 end) as A,
sum(case when emission = 'B' then emission else 0 end) as B,
sum(emission) as total
from t
group by countyid;
I would like to give some idea. We can use pivot table for answer your question
SELECT * from dbo.[Table_1]
PIVOT
(Sum([type_emmssion]) for [polutant] in ([A], [B]) ) as PivotTable
group by [CountryId] ;
you have to use case statemet:
SELECT
SUM( CASE WHEN POLLUTANT = 'A' THEN EMISSION ELSE 0 END) AS A_EMISSION
SUM( CASE WHEN POLLUTANT = 'B' THEN EMISSION ELSE 0 END) AS B_EMISSION
SUM(EMISSION) AS total_emission
FROM table
GROUP BY COUNTYID;

Using Pivot or CTE to horizontalize a query

I am using sql 2008
My data set looks like
Entity Type1 Type2 Balance
1 A R 100
1 B Z 200
1 C R 300
2 A X 1000
2 B Y 2000
My output should look like
Entity A-Type2 A-Balance B-Type2 B-Balance C-Type2 C-Balance
1 R 100 Z 200 R 300
2 X 1000 Y 2000 0
Now I started writing a pivot query, and I think I can get away with MAX because there should be one record per Entity/Type1 combination. But can not figure out how to do two fields in one pivot. Is this possible? Is this something that CTE could help out with?
Easiest is the MAX idea, but with a CASE statement, e.g.:
SELECT
Entity,
MAX(CASE WHEN Type1 = 'A' THEN Type2 ELSE NULL END) AS AType2,
MAX(CASE WHEN Type1 = 'A' THEN Balance ELSE NULL END) AS ABalance,
MAX(CASE WHEN Type1 = 'B' THEN Type2 ELSE NULL END) AS BType2,
MAX(CASE WHEN Type1 = 'B' THEN Balance ELSE NULL END) AS BBalance,
MAX(CASE WHEN Type1 = 'C' THEN Type2 ELSE NULL END) AS CType2,
MAX(CASE WHEN Type1 = 'C' THEN Balance ELSE NULL END) AS CBalance
FROM
...
GROUP BY
Entity
In other words, only use the value when Type1 is a specific value (with other Type1 values getting a null).
You just use conditional aggregation for the pivoting like this:
select Entity,
max(case when Type1 = 'A' then Type2 end) as A_Type2,
max(case when Type1 = 'A' then Balance else 0 end) as A_Balance,
max(case when Type1 = 'B' then Type2 end) as B_Type2,
max(case when Type1 = 'B' then Balance else 0 end) as B_Balance,
max(case when Type1 = 'C' then Type2 end) as C_Type2,
max(case when Type1 = 'C' then Balance else 0 end) as C_Balance
from MyDataSet mds
group by Entity;
Here's doing it with a pivot and a lookup.
SELECT
data.Entity,
ISNULL(a.Type2,'') AS [A-Type2],
ISNULL([A-Balance],0) AS [A-Balance],
ISNULL(b.Type2,'') AS [B-Type2],
ISNULL([B-Balance],0) AS [B-Balance],
ISNULL(c.Type2,'') AS [C-Type2],
ISNULL([C-Balance],0) AS [C-Balance]
FROM
(
SELECT
Entity,
A AS [A-Balance],
B AS [B-Balance],
C AS [C-Balance]
FROM
(
SELECT Entity, Type1, Balance FROM #table
) t
PIVOT (
MAX(Balance)
FOR Type1 IN ([A],[B],[C])
) piv
) data
LEFT OUTER JOIN #table a on a.Type1 = 'A'
AND a.Entity = data.Entity AND a.Balance = [A-Balance]
LEFT OUTER JOIN #table b on b.Type1 = 'B'
AND b.Entity = data.Entity AND b.Balance = [B-Balance]
LEFT OUTER JOIN #table c on c.Type1 = 'C'
AND c.Entity = data.Entity AND c.Balance = [C-Balance]