Pivot or Cross Tab [duplicate] - sql

This question already has answers here:
Pivot in sql server
(4 answers)
Closed 8 years ago.
I have the two tables which need to be linked and present the data in human friendly way. Could you experts point me in right direction, I am bit stuck here.
Both table 1 and table2 are received through ftp and loaded to SQL table in SQL 2008 R2. These two tables are linked by nid and cid together.
Apologies i couldn't copy paste table here, please consider "-" are column separators
Table 1
ID nid cid pid form_key-name
1 4 1 33 Import_Gen_Title-Title
2 4 2 33 Import_Gen_Firstname-Firstname
3 4 3 33 Import_Gen_Surname-Surname
4 4 4 33 Import_Gen_AddressLine1-AddressLine1
5 4 5 33 Import_Gen_AddressLine2-AddressLine2
6 4 6 33 Import_Gen_City-Town/City
7 4 7 33 Import_Gen_Zip-Post code
Table 2
ID nid sid cid data
1 4 14 1 Mr
2 4 14 2 John
3 4 14 3 Smith
4 4 14 4 A Company
5 4 14 5 Nice Street
6 4 14 6 London
7 4 14 7 SE11 0TS
Now how can get this a Result Table like this one below ?
NiD SID Title Firstname Surname AddressLine1 AddressLine2 Town/City-Post code
4 14 Mr John Smith A Company Nice Street London-SE11 0TS

Check my answer for this same question here: Pivot in sql server
I made a stored procedure that uses the PIVOT statement shown by salvoo - but it's more generic, you don't have to know all the columns in advance.
Take a look.
Here is the example using your data - note that the default output of the pivot has the columns in alphabetical order which you don't want - so I used the option to output the pivot to a temp table then queried directly from the temp table to put the columns in the order you wanted.
drop table Fields
go
drop table Data
go
create table Fields
(
ID Integer,
nid Integer,
cid Integer,
pid Integer,
form_key_name varchar(50)
);
go
create table Data
(
ID Integer,
nid Integer,
sid Integer,
cid Integer,
data varchar(50)
);
go
insert into Fields values (1,4,1,33,'Import_Gen_Title-Title')
go
insert into Fields values (2,4,2,33,'Import_Gen_Firstname-Firstname')
go
insert into Fields values (3,4,3,33,'Import_Gen_Surname-Surname')
go
insert into Fields values (4,4,4,33,'Import_Gen_AddressLine1-AddressLine1')
go
insert into Fields values (5,4,5,33,'Import_Gen_AddressLine2-AddressLine2')
go
insert into Fields values (6,4,6,33,'Import_Gen_City-Town/City')
go
insert into Fields values (7,4,7,33,'Import_Gen_Zip-Post code')
go
insert into Data values (1,4,14,1,'Mr')
go
insert into Data values (2,4,14,2,'John')
go
insert into Data values (3,4,14,3,'Smith')
go
insert into Data values (4,4,14,4,'A Company')
go
insert into Data values (5,4,14,5,'Nice Street')
go
insert into Data values (6,4,14,6,'London')
go
insert into Data values (7,4,14,7,'SE11 0TS')
go
declare #mySQL varchar(MAX);
set #mySQL = '
select
f.nid,
d.sid,
right(f.form_key_name, len(f.form_key_name) - charindex(''-'',f.form_key_name)) form_key_name,
d.data
from
Fields f
JOIN Data d
on ( d.nid = f.nid
and d.cid = f.cid )
';
exec pivot_query #mySQL, 'nid, sid', 'form_key_name','max(data)', '##tmppivot';
select
nid,
sid,
Title,
Firstname,
Surname,
AddressLine1,
AddressLine2,
[Town/City],
[Post code]
from
##tmppivot;
go

With Pivot: Fiddle demo
SELECT sid, nid,
[Import_Gen_Title-Title] as Title,
[Import_Gen_Firstname-Firstname] as Name,
[Import_Gen_Surname-Surname] as SurName,
[Import_Gen_AddressLine1-AddressLine1] as Address1,
[Import_Gen_AddressLine2-AddressLine2] as Address2,
[Import_Gen_City-Town/City] as Town,
[Import_Gen_Zip-Post code] as PostCode
FROM
(
SELECT t2.sid, t2.nid, t2.dat, t1.form_key
FROM tab1 t1 INNER JOIN tab2 t2 ON t1.nid = t2.nid AND t1.cid = t2.cid
) x
PIVOT
(
min(x.dat)
for x.form_key in ([Import_Gen_Title-Title],
[Import_Gen_Firstname-Firstname],
[Import_Gen_Surname-Surname],
[Import_Gen_AddressLine1-AddressLine1],
[Import_Gen_AddressLine2-AddressLine2],
[Import_Gen_City-Town/City],
[Import_Gen_Zip-Post code]
)
) pvt
Edit (Added generic version): Fiddle demo
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT ',[' + t.form_key + ']'
FROM tab1 t
group by t.form_key, cid
order by t.cid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'');
SET #query = 'SELECT * FROM
(
SELECT t2.sid, t2.nid, t2.dat, t1.form_key
FROM tab1 t1 INNER JOIN tab2 t2 ON t1.nid = t2.nid AND t1.cid = t2.cid
) x
PIVOT
(
min(x.dat)
FOR x.form_key IN (' + #cols + ')
) pvt;';
execute(#query);

Related

How to create a query to join multiple rows from a different table into single comma delimated column in SQL Server [duplicate]

This question already has answers here:
Simulating group_concat MySQL function in Microsoft SQL Server 2005?
(12 answers)
Closed 4 years ago.
I am using SQL Server 2014, and I have two tables:
number id
------------------
36-23 1
36-23 2
id value
------------------
1 asia
2 europe
The number column is of type varchar. I want to write a query to return the following results:
number Name
---------------------------
36-23 asia,europe
I am wondering how can I do this with the help of query or functions in SQL Server.
I think using STUFF is the easiest way to go forward here.
CREATE TABLE tableID
([number] varchar(50), [id] int)
;
INSERT INTO tableID
([number], [id])
VALUES
('36-23', 1),
('36-23', 2)
;
CREATE TABLE tableLoc
([id] int, [value] varchar(50))
;
INSERT INTO tableLoc
([id], [value])
VALUES
(1, 'asia'),
(2, 'europe')
;
SELECT tableID.number, tableLoc.value INTO temp1
FROM tableID INNER JOIN tableLoc ON tableID.id = tableLoc.id;
SELECT *, STUFF((
SELECT DISTINCT ', ' + value
FROM temp1
WHERE number = t.number
FOR XML PATH('')), 1, 2, '')
FROM (
SELECT DISTINCT number
FROM temp1
) t

Showing data as a column name

I have three tables. I called them as Table A,Table B,Table C.
And I have desired view which I want to get.
Table A
Aid RegNum BID Value
2CE7D0A7 2000000 D5981DFC OFFCRO
9D3C13AA 2000000 C58566C5 YCH - from
9DDB90C4 2000000 812E9E75 Y
Table B is connected to Table A by Table B's foreign key in Table A
Table B
BID Label ColumnName Order
D5981DFC Offered/Change Role StatusChangeCode 0
C58566C5 Offered/Role Change Comments StatusChangeComments 1
812E9E75 Assessed StatusChangeAssessed 2
Table C has foreign key in Table A as well. Reg Num. Reg num is primary key in Table C
Table C
Name Surname RegNum
Etibar Hasanov 2000000
As you see there are column's names which are datas in Table B
DesiredView
Name Surname RegNum StatusChangeCode StatusChangeComments StatusChangeAssessed
Etibar Hasanov 2000000 OFFCRO YCH - from Y
You can achieve this by using PIVOT table. Try something like this,
Create Table TableA(Aid varchar(50), RegNum int, BID Varchar(20), Value varchar(50))
insert into TableA values
('2CE7D0A7', 2000000, 'D5981DFC', 'OFFCRO'),
('9D3C13AA', 2000000, 'C58566C5', 'YCH - from' ),
('9DDB90C4', 2000000, '812E9E75', 'Y')
create Table TableB(BID Varchar(20), Label Varchar(50), ColumnName
Varchar(50), [Order] int)
insert into TableB values
('D5981DFC', 'Offered/Change Role', 'StatusChangeCode', 0),
('C58566C5', 'Offered/Role Change Comments', 'StatusChangeComments', 1),
('812E9E75', 'Assessed', 'StatusChangeAssessed', 2)
Create Table TableC (Name Varchar(20), Surname Varchar(20), RegNum int)
insert into TableC values
('Etibar', 'Hasanov', 2000000)
SELECT *
FROM (
SELECT
Name, SurName, C.RegNum, Value, B.ColumnName
FROM TableC C
JOIN TableA A ON C.RegNum = A.RegNum
JOIN TableB B on B.BID = A.BID
) AS Source
PIVOT
(
MAX(Value)
FOR [ColumnName]
in ( [StatusChangeCode], [StatusChangeComments], [StatusChangeAssessed] )
)AS Pvot
Sql Fiddle Demo
If you are using SQL server 2005, according to Microsoft Technet,
When PIVOT and UNPIVOT are used against databases that are upgraded to
SQL Server 2005 or later, the compatibility level of the database must
be set to 90 or higher.
I first selected columns names. In this table it brings [StatusChangeAssessed],[StatusChangeCode],[StatusChangeComments] . Then in the next query I setted #col ( column names ).
declare #nregnumber nvarchar(10)='2000000';
DECLARE #cols AS NVARCHAR(MAX), #runningquery as nvarchar(max);
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(rn)
from
(
select columnname rn from tableb where exists ( select * from tablea where tablea.bid=tableb.bid and regnum=#nregnumber)
) t
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set #runningquery='
SELECT *
FROM (
SELECT
Name, SurName, C.RegNum, Value, B.ColumnName
FROM TableC C
JOIN TableA A ON C.RegNum = A.RegNum
JOIN TableB B on B.BID = A.BID
) AS Source
PIVOT
(
MAX(Value)
FOR [ColumnName]
in ( '+#cols+')
)AS Pvot'
exec (#runningquery)
Special thanks to Selva.

Trying to concatenate across records [duplicate]

This question already has answers here:
SQL group_concat function in SQL Server [duplicate]
(4 answers)
Closed 8 years ago.
I'm having a bit of a problem that I just can't seem to get my head round. I've got a table that I'm trying to extract some data from. Below is an example of the data.
Id DevId Route
1 1 1
2 1 2
3 1 3
4 1 4
5 2 1
6 2 2
What I want the result to look like would be:
DevId Route
1 1234
2 12
Don't know if I've been looking at it for too long or something, but I just can't work out how to do it.
Any help or suggestions would be greatly appreciated.
Thanks
Alex
Create table ##tmp (id int, name int)
insert into ##tmp values(1,1)
insert into ##tmp values(1,2)
insert into ##tmp values(1,3)
insert into ##tmp values(2,1)
insert into ##tmp values(2,2)
Select id, (Select cast (name as varchar(4))
from ##tmp t2
where t1.id = t2.id
for xml path('')
)
from ##tmp t1
group by id
drop table ##tmp

how create dynamic columns using tables data in sql server 2008?

i have four tables like below in sql server 2008 :
TABLE 1 -> Users
UserID UserName
-----------------------
1 Jhon
TABLE 2 -> PhoneBook
PhonebookID UserID Name MobileNumber
-------------------------------------------------------------------
1 1 MyBrother 252848
TABLE 3 -> PhonebookExtraField
PhonebookExtraFieldID UserID ExtraFieldName
-------------------------------------------------------------
1 1 Age
2 1 Job
3 1 Address
TABLE 4 -> phoneBookExtraFieldData
phoneBookExtraFieldDataID PhonebookExtraFieldID PhonebookID ExtraFieldValue
-----------------------------------------------------------------------------------------
101 1 1 30
102 2 1 Web Developer
103 3 1 A.V. Rose
how can i write a query for output below :
mean i am looking for a way for creating dynamic columns using Tables data...
UserName Phonebook(Name) Phonebook(MobileNumber) Age Job Address
-------------------------------------------------------------------------------------
Jhon MyBrother 252848 30 Web Developer A.V. Rose
what is the best way for doing this job?
how should i change my tables for this purpose?
thanks for attention and advance...
Maybe something like this:
Test data
CREATE TABLE #User
(
UserID INT,
UserName VARCHAR(100)
)
INSERT INTO #User
VALUES(1,'Jhon')
CREATE TABLE #PhoneBook
(
PhonebookID INT,
UserID INT,
Name VARCHAR(100),
MobileNumber INT
)
INSERT INTO #PhoneBook
VALUES(1,1,'MyBrother',252848)
CREATE TABLE #PhonebookExtraField
(
PhonebookExtraFieldID INT,
UserID INT,
ExtraFieldName VARCHAR(100)
)
INSERT INTO #PhonebookExtraField
VALUES(1,1,'Age'),(2,1,'Job'),(3,1,'Address')
CREATE TABLE #PhoneBookExtraFieldData
(
PhoneBookExtraFieldDataID INT,
PhonebookExtraFieldID INT,
PhonebookID INT,
ExtraFieldValue VARCHAR(100)
)
INSERT INTO #PhoneBookExtraFieldData
VALUES(101,1,1,'30'),(102,2,1,'Web Developer'),(103,3,1,'A.V. Rose')
The find the dynamic columns
DECLARE #cols VARCHAR(MAX)
SELECT #cols = COALESCE(#cols + ','+QUOTENAME(ExtraFieldName),
QUOTENAME(ExtraFieldName))
FROM
#PhonebookExtraField
The execute some dynamic sql with a Pivot:
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
#User.UserName,
#PhoneBook.Name AS [Phonebook(Name)],
#PhoneBook.MobileNumber AS [Phonebook(MobileNumber)],
#PhonebookExtraField.ExtraFieldName,
#PhoneBookExtraFieldData.ExtraFieldValue
FROM
#User
JOIN #PhoneBook
ON #User.UserID=#PhoneBook.UserID
JOIN #PhonebookExtraField
ON #PhoneBook.UserID=#PhonebookExtraField.UserID
JOIN #PhoneBookExtraFieldData
ON #PhonebookExtraField.PhonebookExtraFieldID=#PhoneBookExtraFieldData.PhonebookExtraFieldID
) AS p
PIVOT
(
MAX(ExtraFieldValue)
FOR ExtraFieldName IN('+#cols+')
) AS pvt'
EXECUTE(#query)
Then I will clean up after myself:
DROP TABLE #User
DROP TABLE #PhoneBook
DROP TABLE #PhonebookExtraField
DROP TABLE #PhoneBookExtraFieldData
Select
*
from
user as u,
PhoneBook as pb,
PhonebookExtraField as pbf,
phoneBookExtraFieldData as pbdf
where
u.userid=pb.userID
and pb.userID=pbf.userID
and pbf.PhonebookExtraFieldID =pfbd.PhonebookExtraFieldID
and u.Username='Jhon'
Replace * with required column names.

I need to split string in select statement and insert to table

I have a data in one table. I need to copy it to another table. One of the column is text delimited string. So what I'm thinking to select all columns insert get indentity value and with subquery to split based on delimiter and insert it to another table.
Here is the data example
ID Name City Items
1 Michael Miami item|item2|item3|item4|item5
2 Jorge Hallandale item|item2|item3|item4|item5
copy Name, City to one table get identity
and split and copy Items to another table with Identity Column Value
So output should be
Users table
UserID Name City
1 Michael Miami
2 Jorge Hallandale
...
Items table
ItemID UserID Name
1 1 Item
2 1 Item2
3 1 Item3
4 1 Item4
5 2 Item
6 2 Item2
7 2 Item3
8 2 Item4
Not really sure how to do it with T-SQL. Answers with examples would be appreciated
You may create you custom function to split the string in T-Sql. You could then use the Split function as part of a JOIN with your base table to generate the final results for your INSERT statement. Have a look at this post. Hope this help.
You can do this using xml and cross apply.
See the following:
DECLARE #t table (ID int, Name varchar(20), City varchar(20), Items varchar(max));
INSERT #t
SELECT 1,'Michael','Miami' ,'item|item2|item3|item4|item5' UNION
SELECT 2,'Jorge' ,'Hallandale','item|item2|item3|item4|item5'
DECLARE #u table (UserID int identity(1,1), Name varchar(20), City varchar(20));
INSERT #u (Name, City)
SELECT DISTINCT Name, City FROM #t
DECLARE #i table (ItemID int identity(1,1), UserID int, Name varchar(20));
WITH cte_Items (Name, Items) as (
SELECT
Name
,CAST(REPLACE('<r><i>' + Items + '</i></r>','|','</i><i>') as xml) as Items
FROM
#t
)
INSERT #i (UserID, Name)
SELECT
u.UserID
,s.Name as Name
FROM
cte_Items t
CROSS APPLY (SELECT i.value('.','varchar(20)') as Name FROM t.Items.nodes('//r/i') as x(i) ) s
INNER JOIN #u u ON t.Name = u.Name
SELECT * FROM #i
See more here:
http://www.kodyaz.com/articles/t-sql-convert-split-delimeted-string-as-rows-using-xml.aspx
Can you accomplish this with recursion? My T-SQL is rusty but this may help send you in the right direction:
WITH CteList AS (
SELECT 0 AS ItemId
, 0 AS DelimPos
, 0 AS Item_Num
, CAST('' AS VARCHAR(100)) AS Item
, Items AS Remainder
FROM Table1
UNION ALL
SELECT Row_Number() OVER(ORDER BY UserID) AS ItemId
, UserID
, CASE WHEN CHARINDEX('|', Remainder) > 0
THEN CHARINDXEX('|', Remainder)
ELSE LEN(Remainder)
END AS dpos
, Item_num + 1 as Item_Num
, REPLACE(Remainder, '|', '') AS Element
, right(Remainder, dpos+1) AS Remainder
FROM CteList
WHERE dpos > 0
AND ItemNum < 20 /* Force a MAX depth for recursion */
)
SELECT ItemId
, Item
FROM CteList
WHERE item_num > 0
ORDER BY ItemID, Item_Num