I think that PIVOT will help me accomplish this, but I can't get anything started. I am having serious SQL brain farts today, I need some help.
Here is the output I have now:
Id Name Question Answer
0 Test Vault A
0 Test Container 1
1 Foo Vault B
1 Foo Container 2
And this is my desired output:
Id Name Vault Container
0 Test A 1
1 Foo B 2
Can this be done?
If that is impossible or terribly complex to do, I have an alternate way to approach this. The output for my alternate query is:
Id Name VaultId ContainerId
0 Test A NULL
0 Test NULL 1
1 Foo B NULL
1 Foo NULL 2
And here I need to be able to suppress it into one row per Id/Name. I can't remember how to do either of these!
DECLARE #Test TABLE
(
Id INT
,[Name]VARCHAR(10) NOT NULL
,Question VARCHAR(10) NOT NULL,
Answer VARCHAR(10)
);
INSERT #Test VALUES (0,'test1', 'vault','a');
INSERT #Test VALUES (0,'test1', 'Container ','1');
INSERT #Test VALUES (1,'test4', 'vault','b');
INSERT #Test VALUES (1,'test4', 'Container','2');
;WITH CTE
AS
(
SELECT t.id, t.[Name], t.[Question ] ,t.Answer
FROM #Test t
)
SELECT *
FROM CTE
PIVOT ( max(answer) FOR Question IN (vault,container) ) f;
You could do this with a Static Pivot:
create table temp
(
id int,
name varchar(10),
question varchar(10),
answer varchar(10)
)
INSERT into temp VALUES (0,'test', 'vault','a');
INSERT into temp VALUES (0,'test', 'Container','1');
INSERT into temp VALUES (1,'foo', 'vault','b');
INSERT into temp VALUES (1,'foo', 'Container','2');
select *
from
(
select id, name, question, answer
from temp
) x
pivot
(
max(answer)
for question in ([container], [vault])
) p
drop table temp
or a dynamic pivot
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.question)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id, name, ' + #cols + ' from
(
select id, name, question, answer
from temp
) x
pivot
(
max(answer)
for question in (' + #cols + ')
) p '
execute(#query)
both will give you the same results:
Yeah PIVOT is what you need here :). Assuming your table is called MyPivot Try:
SELECT Id, Name, [Vault], [Container]
FROM (SELECT Id, Name, Question, Answer FROM MyPivot) AS SourceTable
PIVOT (MAX(Answer) FOR Question in (Vault, Container)) as p;
EDIT: To demonstrate what that syntax means, see the following breakdown:
PIVOT (<aggregate function>(<column being aggregated>)
FOR <column that contains the values that will become column headers>
IN ( [first pivoted column], [second pivoted column])
Related
I have a table which i would like to pivot to show how many categories a person is affiliated with...
I would like to pivot this to show:
There are a lot more members and categories but the theory i believe should be the same.
I have attempted this however it only shows the first line for each.
Thanks in advance
Will
#Will, this is the logic you need. Basically a pivot function on the column of interest.
DECLARE #tbl TABLE (RegNo varchar(20), Category varchar(20), Number int)
INSERT INTO #tbl
SELECT 'R1050162', 'Gym', 1 UNION ALL
SELECT 'R1050162', 'Personal Trainer', 1 UNION ALL
SELECT 'R0093126', 'Group Exercise', 1 UNION ALL
SELECT 'R0143614', 'Yoga Teacher', 1
SELECT *
FROM
#tbl
PIVOT
(
SUM(Number)
FOR Category IN ([Gym], [Personal Trainer], [Group Exercise], [Yoga Teacher]
)
) AS PivotTable;
Output is below:
You need to use just sum the Number field in PIVOT function and for numerous categories get a category list:
DECLARE #categories AS NVARCHAR(MAX),
#your_query AS NVARCHAR(MAX);
select #categories = STUFF((SELECT distinct ',' + QUOTENAME(Category)
FROM your_table
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT RegNo, ' + #categories + ' from
(
SELECT RegNo, Category, Number FROM your_table) tab
PIVOT
(
SUM(Number)
FOR Category IN (' + #categories + ')
) p iv
ORDER BY piv.RegNo'
execute(#your_query)
I have a table like this in my database (SQL Server 2008)
ID Type Desc
--------------------------------
C-0 Assets No damage
C-0 Environment No impact
C-0 People No injury or health effect
C-0 Reputation No impact
C-1 Assets Slight damage
C-1 Environment Slight environmental damage
C-1 People First Aid Case (FAC)
C-1 Reputation Slight impact; Compaints from local community
i have to display the Assets, People, Environment and Reputation as columns and display matched Desc as values. But when i run the pivot query, all my values are null.
Can somebody look into my query ans tell me where i am doing wrong?
Select severity_id,pt.[1] As People, [2] as Assets , [3] as Env, [4] as Rep
FROM
(
select * from COMM.Consequence
) As Temp
PIVOT
(
max([DESCRIPTION])
FOR [TYPE] In([1], [2], [3], [4])
) As pt
Here is my output
ID People Assets Env Rep
-----------------------------------
C-0 NULL NULL NULL NULL
C-1 NULL NULL NULL NULL
C-2 NULL NULL NULL NULL
C-3 NULL NULL NULL NULL
C-4 NULL NULL NULL NULL
C-5 NULL NULL NULL NULL
Select severity_id, pt.People, Assets, Environment, Reputation
FROM
(
select * from COMM.Consequence
) As Temp
PIVOT
(
max([DESCRIPTION])
FOR [TYPE] In([People], [Assets], [Environment], [Reputation])
) As pt
I recreated this in sql server and it works just fine.
I'm trying to convert this to work when one does not know what the content will be in the TYPE and DESCRIPTION columns.
I was also using this as a guide. (Convert Rows to columns using 'Pivot' in SQL Server)
EDIT ----
Here is my solution for the above where you DON'T KNOW the content in either field....
-- setup commands
drop table #mytemp
go
create table #mytemp (
id varchar(10),
Metal_01 varchar(30),
Metal_02 varchar(100)
)
-- insert the data
insert into #mytemp
select 'C-0','Metal One','Metal_One' union all
select 'C-0','Metal & Two','Metal_Two' union all
select 'C-1','Metal One','Metal_One' union all
select 'C-1','Metal (Four)','Metal_Four' union all
select 'C-2','Metal (Four)','Metal_Four' union all
select 'C-2','Metal / Six','Metal_Six' union all
select 'C-3','Metal Seven','Metal_Seven' union all
select 'C-3','Metal Eight','Metal_Eight'
-- prepare the data for rotating:
drop table #mytemp_ReadyForRotate
select *,
replace(
replace(
replace(
replace(
replace(
mt.Metal_01,space(1),'_'
)
,'(','_'
)
,')','_'
)
,'/','_'
)
,'&','_'
)
as Metal_No_Spaces
into #mytemp_ReadyForRotate
from #mytemp mt
select 'This is the content of "#mytemp_ReadyForRotate"' as mynote, * from #mytemp_ReadyForRotate
-- this is for when you KNOW the content:
-- in this query I am able to put the content that has the punctuation in the cell under the appropriate column header
Select id, pt.Metal_One, Metal_Two, Metal_Four, Metal_Six, Metal_Seven,Metal_Eight
FROM
(
select * from #mytemp
) As Temp
PIVOT
(
max(Metal_01)
FOR Metal_02 In(
Metal_One,
Metal_Two,
Metal_Four,
Metal_Six,
Metal_Seven,
Metal_Eight
)
) As pt
-- this is for when you DON'T KNOW the content:
-- in this query I am UNABLE to put the content that has the punctuation in the cell under the appropriate column header
-- unknown as to why it gives me so much grief - just can't get it to work like the above
-- it WORKS just fine but not with the punctuation field
drop table ##csr_Metals_Rotated
go
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#InsertIntoTempTable as nvarchar(4000)
select #cols = STUFF((SELECT ',' + QUOTENAME(Metal_No_Spaces)
from #mytemp_ReadyForRotate
group by Metal_No_Spaces
order by Metal_No_Spaces
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id,' + #cols + ' into ##csr_Metals_Rotated from
(
select id as id, Metal_No_Spaces
from #mytemp_ReadyForRotate
) x
pivot
(
max(Metal_No_Spaces)
for Metal_No_Spaces in (' + #cols + ')
) p '
execute(#query);
select * from ##csr_Metals_Rotated
I have a data column with values like this:
Table1
ID|GROUPNAME |MEMBER
1|GRP1_ML_Unit1_Role1|GRP=User1,DC=com;GRP=User2,DC=com
2|GRP2_ML_Unit2_Role2|GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com
3|GRP3_ML_Unit3_Role3|GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com
Expected output
ID|GRP1 |GRP2|GRP3 |GRP4 |MEM1 |MEM2 |MEM3 |MEM4|MEM5|
1 |GRP1 |ML |Unit1|Role1|GRP=User1,DC=com|GRP=User2,DC=com| | |
2 |GRP2 |ML |Unit2|Role2|GRP=User3,DC=com|GRP=User4,DC=com|GRP=User5,DC=com| |
3 |GRP3 |ML |Unit3|Role3|GRP=User6,DC=com|GRP=User7,DC=com|GRP=User8,DC=com|GRP=User8,DC=com |
Thanks,
Ryl
The completed solution is below with the sample data you gave me.
First, create a temp table and fill it with data.
-- Drop the table
drop table #member;
go
-- Sample table
create table #member
(
member_id int not null,
group_name varchar(256),
member_data varchar(8000)
);
go
-- Sample data
insert into #member values
(1, 'GRP1_ML_Unit1_Role1', 'GRP=User1,DC=com;GRP=User2,DC=com'),
(2, 'GRP2_ML_Unit2_Role2', 'GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com'),
(3, 'GRP3_ML_Unit3_Role3', 'GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com');
go
-- Show the data
select * from #member;
go
Second, copy down one of the many string splitters out there. I ended up installing Jeff Moden's string spliter for 8K max strings.
The query is almost there. However, each column we want is a row. We need to dynamically pivot the table.
--
-- Almost there!
--
-- Data in columns, instead of rows
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
go
Last but not least, figure out the number of columns. Write dynamic TSQL to pivot our dat and get our result.
--
-- Write dynamic sql to solve
--
DECLARE
#cols AS nvarchar(MAX),
#query AS nvarchar(MAX);
-- Get a dynamic number of columns
SET #cols = STUFF(
(
SELECT distinct ',' + QUOTENAME(c.cols_name)
FROM
(
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
) as c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
print #cols;
-- Make dynamic pivot query
set #query = 'SELECT member_id as ID1, group_name as GROUP1, ' + #cols + ' from
(
select m.member_id, m.group_name, s.Item as cols_data, ''MEM'' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data, '';'') s
) x
pivot
(
max(cols_data)
for cols_name in (' + #cols + ')
) p ';
execute(#query)
A screen shot of the results in the desired format.
How to transform this:
ID Name Description
1 Test1a TestDesc1a
1 Test1b TestDesc1b
2 Test2a TestDesc2a
2 Test2b TestDesc2b
into this:
ID Column 1 2
1 Name test1a test1b
1 Description testDesc1a testDesc1b
You ask for complex pivoting table. Read about this here: http://msdn.microsoft.com/en-us/library/ms177410.aspx
You need to use a PIVOT query.
A basic discussion of PIVOT queries can be found at [MSDN][1].
This is a tricky question to solve, however the output specified is not proper/ conflicting. Below is similar solution which you can try
Sample Table creation:
CREATE TABLE [dbo].[TestTable](
[Id] [int] NULL,
[Name] [nvarchar](50) NULL,
[Description] [nvarchar](50) NULL)
Inserting sample values:
INSERT INTO TestTable VALUES (1,'Test1a','TestDesc1a')
INSERT INTO TestTable VALUES (2,'Test1b','TestDesc1b')
INSERT INTO TestTable VALUES (3,'Test2a','TestDesc2a')
INSERT INTO TestTable VALUES (4,'Test2b','TestDesc2b')
Query to get the desired output using Pivot:
SELECT 'Name' AS [Column], [1], [2],[3],[4]
FROM
(SELECT Name, id from TestTable) AS ST
PIVOT
(Max(Name) FOR ID IN ([1], [2],[3],[4])) AS PT
UNION
SELECT 'Description' AS [Column], [1], [2],[3],[4]
FROM
(SELECT id,[Description] from TestTable) AS ST
PIVOT
(Max([Description]) FOR ID IN ([1], [2],[3],[4])) AS PT
ORDER BY [Column] DESC
OutPut:
Column 1 2 3 4
Name Test1a Test1b Test2a Test2b
Description TestDesc1a TestDesc1b TestDesc2a TestDesc2b
Hope this helps to solve your question.
You can use a static PIVOT if you only are going to have a few columns but I am guessing that you will have more than 2 IDs so you will probably want to use a Dynamic PIVOT for this query. Using a dynamic pivot will allow you to have more than the two ids you provided, it will grab all of the Ids from the table and then PIVOT:
create table temp
(
id int,
name varchar(10),
description varchar(20)
)
insert into temp values (1, 'Test1a', 'TestDesc1a')
insert into temp values (1, 'Test1b', 'TestDesc1b')
insert into temp values (2, 'Test2a', 'TestDesc2a')
insert into temp values (2, 'Test2b', 'TestDesc2b')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.id)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT ''Name'' as [Column], ' + #cols + ' from
(
select id
, name
from temp
) x
pivot
(
max(name)
for id in (' + #cols + ')
) p
UNION
SELECT ''Description'' as [Column], ' + #cols + ' from
(
select id
, description
from temp
) x
pivot
(
max(description)
for id in (' + #cols + ')
) p '
execute(#query)
drop table temp
Results:
Column 1 2
Description TestDesc1b TestDesc2b
Name Test1b Test2b
I want to pivot and turn an existing table and generate a report(cross tabulated). You see vals column is determined by unique combination of date_a and date_e columns. I don't know how to do this.
Something like this:
Test data
CREATE TABLE #tbl(date_a DATE,date_e DATE, vals FLOAT)
INSERT INTO #tbl
VALUES
('2/29/2012','1/1/2013',28.47),
('2/29/2012','2/1/2013',27.42),
('2/29/2012','3/1/2013',24.36),
('3/1/2012','1/1/2013',28.5),
('3/1/2012','2/1/2013',27.35),
('3/1/2012','3/1/2013',24.39),
('3/6/2012','1/1/2013',27.75),
('3/6/2012','2/1/2013',26.63),
('3/6/2012','3/1/2013',23.66)
Query
SELECT
*
FROM
(
SELECT
tbl.date_a,
tbl.date_e,
vals
FROM
#tbl AS tbl
) AS SourceTable
PIVOT
(
SUM(vals)
FOR date_e IN ([1/1/2013],[2/1/2013],[3/1/2013])
) AS pvt
DROP TABLE #tbl
EDIT
If you do not know how many columns there is then you need to do a dynamic pivot. Like this:
The unique columns
DECLARE #cols VARCHAR(MAX)
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY date_e ORDER BY date_e) AS RowNbr,
tbl.*
FROM
#tbl AS tbl
)
SELECT #cols=STUFF
(
(
SELECT
',' +QUOTENAME(date_e)
FROM
CTE
WHERE
CTE.RowNbr=1
FOR XML PATH('')
)
,1,1,'')
Dynamic pivot
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
tbl.date_a,
tbl.date_e,
vals
FROM
#tbl AS tbl
) AS SourceTable
PIVOT
(
SUM(vals)
FOR date_e IN ('+#cols+')
) AS pvt'
EXECUTE(#query)