sql query to show results vertically - sql

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

Related

SQL convert rows to one Column

I have a table,
Output before pivoting:
keli | onoma
-----+---------------
name | Step1
a1 | DSP
a2 | Tekmiriosi
Expected output:
Step1 | DSP | Tekmiriosi
How to do that for three or more rows but always with to one-row column?
You can use conditional aggregation:
select max(onoma) filter (where keli = 'name'),
max(onoma) filter (where keli = 'a1'),
max(onoma) filter (where keli = 'a2')
from t;
However, I might suggest that you if you want all values in a single row that you just use arrays:
select array_agg(keli)
from t;
you can use following query
create table temp
(
keli varchar(100),
onoma varchar(100)
)
insert into temp values ('name', 'Step1')
insert into temp values ('a1', 'DSP')
insert into temp values ('a2', 'Tekmiriosi')
DECLARE #column AS NVARCHAR(MAX)
DECLARE #qry AS NVARCHAR(MAX)
SET #column = STUFF((SELECT distinct ',' + QUOTENAME(c.onoma)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #qry = 'SELECT ' + #column + ' from
(
select onoma
from temp
) x
pivot
(
max(onoma)
for onoma in (' + #column + ')
) p '
execute(#qry)
drop table temp

pivot data from one table

input table
country tag short
UK F1 Units
UK F2 Volume
UK F3 Value
FR T3 Units
FR T2 Volume
FR T1 Value
result output i want :
country Units Volume Value
uk f1 f2 f3
fr t1 t2 t3
If there are a fixed number of different short values, simply use case expressions to do conditional aggregation:
select country,
max(case when short = 'Units' then tag end) as Units,
max(case when short = 'Volume' then tag end) as Volume,
max(case when short = 'Value' then tag end) as val
from tablename
group by country
For solution you have to use dynamic pivoting.
create table #temp
(
country varchar(30),tag varchar(20),short varchar(300)
)
insert into #temp values ('UK', 'F1', 'Units')
insert into #temp values ('UK', 'F2' , 'Volume')
insert into #temp values ('UK' ,'F3', 'Value')
insert into #temp values ('FR', 'T3' , 'Units')
insert into #temp values ('FR' , 'T2', 'Volume')
insert into #temp values ('FR', 'T1' , 'Value')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.short)
FROM #temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT country, ' + #cols + ' from
(
select country
, tag
, short
from #temp
) x
pivot
(
max(tag)
for short in (' + #cols + ')
) p '
execute(#query)
drop table #temp
Table Structure
CREATE TABLE tablename
(
[country] [NVARCHAR](10) NULL,
[tag] [NVARCHAR](10) NULL,
[short] [NVARCHAR](10) NULL
)
INSERT INTO tablename
VALUES
('UK','F1','Units'),
('UK','F2','Volume'),
('UK','F3','Value'),
('FR','T3','Units'),
('FR','T2','Volume'),
('FR','T1','Value');
Using Pivot function
SELECT *
FROM tablename
PIVOT ( Max(tag)
FOR short IN ([Units], [volume], [Value]) ) piv;
Online Demo: Link
Using Dynamic SQL PIVOT
DECLARE #cols AS NVARCHAR(max),
#query AS NVARCHAR(max)
SELECT #cols = Stuff((SELECT distinct ',' + Quotename(short)
FROM tablename
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1,'');
SET #query = 'SELECT *
FROM tablename
PIVOT ( Max(tag)
FOR short IN (' + #cols + ') ) piv;';
EXECUTE(#query);
Online Demo: Link
Result
+---------+-------+--------+-------+
| country | Units | volume | Value |
+---------+-------+--------+-------+
| FR | T3 | T2 | T1 |
| UK | F1 | F2 | F3 |
+---------+-------+--------+-------+

How convert rows to columns in SQL Server

I'm looking for an efficient way to convert rows to columns with dynamic column names in SQL Server. I heard that PIVOT is not very fast, and I need to deal with a lot of records.
This is my example:
Id Name Type Address
----------------------------------
1 A Vendor Add1
2 B Vendor Add2
3 C Purchaser Add3
4 D Agent Add4
Required result:
Vendor Name Vendor Address Vendor 1 Name Vendor 1 Address Purchaser Name Purchaser Address Agent Name Agent Address
A Add1 B Add2 C Add3 D Add4
How can I build the result in which column names will create dynamic like if first value is vendor and if second time vendor will come then it will display look like vendor 1 + Name or Address?
You could use following table:
CREATE TABLE TEMP (
DATE DATETIME
,category VARCHAR(3)
,amount MONEY
)
INSERT INTO TEMP
VALUES (
'1/1/2012'
,'ABC'
,1000.00
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'DEF'
,500.00
)
INSERT INTO TEMP
VALUES (
'2/1/2012'
,'GHI'
,800.00
)
INSERT INTO TEMP
VALUES (
'2/10/2012'
,'DEF'
,700.00
)
INSERT INTO TEMP
VALUES (
'3/1/2012'
,'ABC'
,1100.00
)
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.category)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT date, ' + #cols + ' from
(
select date
, amount
, category
from temp
) x
pivot
(
max(amount)
for category in (' + #cols + ')
) p '
execute(#query)
drop table temp

Splitting a string of unlimited length SQL

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.

Constructing a PIVOT

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])