Split multiple column and store into temp table - sql-server

I have the sample data:
Table: tblsampledata
create table tblsampledata
(
column1 varchar(50),
column2 varchar(50)
);
insert into tblsampledata values('Bob Frapples','Gail Forcewind');
insert into tblsampledata values('Paul Molive','Mario Speedwagon');
And I have column mapping table with table name:
Table: tblmapping
create table tblmapping
(
tblname varchar(100),
columnmap varchar(max)
);
insert into tblmapping values('tblsampledata','[column1]|[column2]');
Note: I want to split the column data which are exists in tblmapping of table name in column tblname and store it into temp table.
Expected Result: #TempTable
column1 column2
---------------------
Bob Gail
Frapples Forcewind
Paul Mario
Molive Speedwagon

You need to use dynamic query to acheive this.
You can try like following.
select #xml = Cast(( '<X>' + Replace(columnmap, '|', '</X><X>') + '</X>' ) AS XML)
from tblmapping where tblname =#tablename
DECLARE #query AS NVARCHAR(max) = 'select ' + Stuff((SELECT DISTINCT ', ' + value
FROM (
SELECT n.value('.', 'varchar(100)') AS value
FROM #xml.nodes('X') AS T(n)
)t
FOR xml path(''), type).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
+ ' from ' + #tablename;
exec sp_executesql #query
Online Demo
To split the column 1 and Column 2 you can use query like following.
SELECT CASE
WHEN n = 1 THEN LEFT(column1, Charindex(' ', column1) - 1)
WHEN n = 2 THEN RIGHT(column1, Charindex(' ', Reverse(column1)) - 1)
END AS column1,
CASE
WHEN n = 1 THEN LEFT(column2, Charindex(' ', column2) - 1)
WHEN n = 2 THEN RIGHT(column2, Charindex(' ', Reverse(column2)) - 1)
END AS column2
FROM tblsampledata t1
CROSS JOIN ( VALUES(1),(2) )t(n)
Full Demo using dynamic query

Related

MS SQL.Transform rows into columns

I have a simple table. As a result I need to get names of numeric columns and paste like rows and then paste its values like columns.Here is an example of table:
As a result I need to receive something like this:
I tried to get the result with PIVOT, but I have not the correct answer.
select * from (
select col1, 'val' + cast(row_number()over(partition by col1 order by col1) as nvarchar(20)) ColVal
from mytbl
) tmp
pivot (
min(col1) for ColVal in (val1,val2)
) pvt
In this case you need to unpivot first, then pivot back:
DROP TABLE IF EXISTS dbo.temp
DROP TABLE IF EXISTS dbo.temp2
CREATE table dbo.temp(col1 INT, col2 INT, col3 INT);
INSERT INTO temp VALUES (27,93,80),(32,84,72),(46,68,75),(38,79,73),(23,77,84);
DECLARE #colsUnpivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
-- first unpivot to key value pairs
select #colsUnpivot
= stuff((select ','+quotename(C.column_name)
from information_schema.columns as C
where C.table_name = 'temp' and
C.column_name like 'col%'
for xml path('')), 1, 1, '')
set #query
= 'SELECT ''val'' + convert(varchar, i) as id,
name,
val
INTO dbo.temp2
FROM
(
SELECT *, row_number() over (order by col1) as i
from temp
) a
UNPIVOT
(
val
FOR name IN ('+ #colsunpivot +')
) u'
exec sp_executesql #query;
-- now pivot back
DECLARE #columns NVARCHAR(MAX), #sql NVARCHAR(MAX);
SET #columns = N'';
SELECT #columns += N', ' + QUOTENAME(id)
FROM (SELECT DISTINCT id FROM dbo.temp2) AS x;
SET #query = N'
SELECT name, ' + STUFF(#columns, 1, 2, '') + '
FROM
(
SELECT id, name, val
from temp2
) AS j
PIVOT
(
SUM(val) FOR id IN ('
+ STUFF(REPLACE(#columns, ', [', ',['), 1, 1, '')
+ ')
) AS p;';
EXEC sp_executesql #query;
I adapted two separate scripts I had lying around, hence the two parts and the intermediate temp2 table. You can probably mash both together with a bit of elbow grease, but this should get you most of the way there.
Also adding the id (to get val1, val2 etc) dynamically means the results are sorted by col1 (val1 will have the lowest col1) but you were doing something similar in your attempt so I assume this is ok. If not, you will need to add an identity column to the data first and use that in place of the row_number()

Concatenate dynamically pivoted columns for a variable number of columns

I have been able to successfully pivot different field values into separate columns but what I want is to concatenate all of those separate (pivoted) columns into one column. I don't know how many pivoted columns that I end up with at runtime so I can't just use Column1 + Column2 + Column3 etc.
Here is my sql
--Create a table variable to hold my source data
declare #datatable table
(
OrderId int,
ProductId int,
ClientName varchar(50)
)
--insert some data
insert into #datatable values (1, 2, 'Joe Bloggs')
insert into #datatable values (1, 2, 'Frank Bloggs')
--Create a temp table
--that introduces a new field (called Header)
--to give me column names for my pivoted data
IF OBJECT_ID('tempdb..#PivotedClients') IS NOT NULL DROP TABLE #PivotedClients
create table #PivotedClients
(
OrderId int,
ProductId int,
ClientName varchar(50),
Header varchar(100)
)
insert into #PivotedClients
select OrderId,
ProductId,
ClientName,
'Client ' + Cast(Rank() Over (Partition by OrderId
order by ClientName) as varchar(3))
from #datatable
--Create variables to hold my column names
--and my (dynamic) sql
declare #pivotcolumns nvarchar(max),
#colsWithNoNulls nvarchar(max),
#sqlquery nvarchar(max)
set #pivotcolumns = STUFF(
(
select distinct ',' + QUOTENAME(Header)
from #PivotedClients
for XML PATH (''), TYPE
).value('.', 'nvarchar(max)')
,1,1,'')
set #colsWithNoNulls = STUFF(
(
SELECT DISTINCT ',ISNULL(' + QUOTENAME(Header) + ', '''') ' + QUOTENAME(Header)
FROM #PivotedClients
for XML PATH (''), TYPE
).value('.', 'NVARCHAR(max)')
,1,1,''
)
if OBJECT_ID('tempdb..##Clients ') is not null drop TABLE ##Clients
set #sqlquery = 'select distinct OrderId,
ProductID,
' + #colsWithNoNulls + '
into ##Clients
from
(
select OrderId,
ClientName,
ProductID,
Header
from #PivotedClients) x
pivot
(
Max(ClientName)
for Header in (' + #pivotcolumns + ')
) p'
exec sp_executesql #sqlquery
----
select *
from ##Clients
----
The record set that I currently end up with is:
OrderId ProductId Client1 Client 2
1 2 Frank Bloggs Joe Blogs
What I want is:
OrderID ProductId Clients
1 2 Frank Bloggs Joe Bloggs
I don't know how many 'pivoted' columns that I will end up with at runtime so I can't just use Client1 + Client2 etc
Just need to change your #colsWithNoNulls to perform the string concatenation
set #colsWithNoNulls = STUFF(
(
SELECT DISTINCT '+ '' '' + ISNULL(' + QUOTENAME(Header) + ', '''')'
FROM #PivotedClients
for XML PATH (''), TYPE
).value('.', 'NVARCHAR(max)')
, 1, 1, '') + 'AS Clients'
Also you can do a print #sqlquery before sp_executesql. this will helps you debug your dynamic query

t-sql Pivot on all values

I have a table with around 10 rows. I want to pivot on all values in one column to a one-row multi column result. It looks as though there is no way to get around the "For ContactTypeID in ([1],[2])" syntax.
ContactTypeID int
ContactType varchar(20)
Sample data:
1 Customer
2 Vendor
...
5 BillTo
I want to return a single row with
Customer Vendor BillTo, etc
1 2 5
But like I said, I don't want to have to specify each ContactTypeID by number. Is there way to specify "for all"?
Thank you.
You need a dynamic pivot.
Here's the code, for your reference. Hope it helps.
CREATE TABLE tablename (ContactTypeID int, ContactType varchar(20));
INSERT INTO tablename VALUES (1, 'Customer'), (2, 'Vendor'), (5, 'BillTo');
DECLARE #cols NVARCHAR (MAX);
SELECT #cols = COALESCE (#cols + ',[' + ContactType + ']',
'[' + ContactType + ']')
FROM (SELECT DISTINCT [ContactType] FROM tablename) PV
ORDER BY [ContactType]
DECLARE #query NVARCHAR(MAX)
SET #query = '
SELECT * FROM
(
SELECT * FROM tablename
) x
PIVOT
(
MIN(ContactTypeID)
FOR [ContactType] IN (' + #cols + ')
) p
'
EXEC SP_EXECUTESQL #query;

How do i pivot a table?

I have a dynamic single row Table like:
PersonId|FirstName|LastName|Address|PhoneNumber
-----------------------------------------------
1 Anuj Tamrakar NY +525418
I want to pivot this table and want an output in temp table like:
PersonalDetails|Value
----------------------
PersonId 1
FirstName Anuj
LastName Tamrakar
Address NY
PhoneNumber +525418
The first Table is a dynamic single row temp table. For this example, I have 5 columns. I may have more or less columns depending on my criteria
You actually want to UNPIVOT:
SELECT PersonalDetails, Value
FROM
(SELECT CAST([PersonId] AS VARCHAR(MAX)) AS [PersonId],
CAST([FirstName] AS VARCHAR(MAX)) AS [FirstName],
CAST([LastName] AS VARCHAR(MAX)) AS [LastName],
CAST([Address] AS VARCHAR(MAX)) AS [Address],
CAST([PhoneNumber] AS VARCHAR(MAX)) AS [PhoneNumber]
FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN
([PersonId], [FirstName], [LastName], [Address], [PhoneNumber])
) AS unpvt;
All 'to-be-unpivoted' fields have to be of the same type, hence the use of CAST.
Demo here
For a dynamic number of columns you have to use dynamic sql:
DECLARE #cols VARCHAR(MAX) = ''
DECLARE #cast_cols VARCHAR(MAX) = ''
DECLARE #qry VARCHAR(MAX)
SELECT #cols = #cols + ',[' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SELECT #cast_cols = #cast_cols + ',CAST([' + COLUMN_NAME + '] AS VARCHAR(MAX)) AS [' + COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'mytable' AND TABLE_SCHEMA='dbo'
SET #cols = STUFF(#cols, 1, 1, '')
SET #cast_cols = STUFF(#cast_cols, 1, 1, '')
SET #qry = 'SELECT PersonalDetails, Value FROM ('
+ #cast_cols +
'FROM mytable) p
UNPIVOT
(Value FOR PersonalDetails IN (' + #cols + ')
) AS unpvt'
EXEC (#qry)
If you really have a single row in the original table, then you can use a series of UNION operations to get your output:
SELECT 'PersonId' AS PersonalDetails, PersonId AS Value
FROM yourTable
UNION ALL
SELECT 'FirstName' AS PersonalDetails, FirstName AS Value
FROM yourTable
UNION ALL
SELECT 'LastName' AS PersonalDetails, LastName AS Value
FROM yourTable
UNION ALL
SELECT 'Address' AS PersonalDetails, Address AS Value
FROM yourTable
UNION ALL
SELECT 'PhoneNumber' AS PersonalDetails, PhoneNumber AS Value
FROM yourTable
SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('dbo.yourTableName')
This gives you your column names. You simply insert the column names in your new table and use ``, insert into temp(PersonalDetails, Value) values(column1,select column1 from SingleRowTable

TSQL transform row values into one column table

Source Table
Col1 |Col2 |Col3 |Col4 | Col5
----------------------------------
hi | this | is | a | test
Destination Table
RowValues|
----------
hi
this
is
a
test
I am using Dynamic SQL.
Any help ?
This is my code , just change table name and the Id in the where clause to what suits you
DECLARE #sql nVARCHAR(max), #TableName nvarchar(100), #where nvarchar(max)
set #TableName = 'stockItems'
set #where= ' where id = 2'
select #sql ='Select '
select #sql = #sql+ + ' '''+ [name] +' = ''+ cast(' + [name] + ' as nvarchar(10)) as '+[name]+', '
from sys.columns where object_name (object_id) = #TableName
set #sql = stuff(#sql, len(#sql), 1, '') + ' From '+#TableName+ #where
print #sql
set #sql = REPLACE(#sql,', From',' From')
set #sql = #sql + ' '
print #sql
exec(#sql)
Now I need to create a new table that has one column that hold holds each value as a row
Thanks to #Mahmoud-Gamal
The solution should be something like below
declare #cols nvarchar(max)
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(column_name)
FROM information_schema.columns
WHERE table_name = 'vehicles'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
declare #statement nvarchar(max)
set #statement ='
SELECT
ColumnName, Value
FROM
Vehicles
UNPIVOT
(
Value
FOR ColumnName
IN
(
'+#cols+'
)
)
AS A'
execute(#statement)
Please change the "vehicle" table name to any table on your database that has columns from different types (datetime, int and nvarchar) and the below error is shown
Any help ?
The type of column "Description" conflicts with the type of other columns specified in the UNPIVOT list.
Use the UNPIVOT table operator:
SELECT col AS RowValues
FROM table1 AS t
UNPIVOT
(
col
FOR value IN([col1],
[col2],
[col3],
[col4],
[col5])
) AS u;
SQL Fiddle Demo
This will give you:
| ROWVALUES |
|-----------|
| hi |
| this |
| is |
| a |
| test |
Update:
In case you don't know the names of the columns, and you want to do this dynamically, you have to do this using dynamic SQL.
But the problem is how to get the columns names?
You can get the columns names from the information_schema.columns, then concatenate them in one sql, then replace the columns' names in the UNPIVOT with this string, and execute that statement dynamically like this:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(column_name)
FROM information_schema.columns
WHERE table_name = 'Table1'
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SELECT #query = ' SELECT col AS RowValues
FROM table1 AS t
UNPIVOT
(
val
FOR col IN ( ' + #cols + ' )
) AS u;';
EXECUTE(#query);
Updated SQL Fiddle Demo
I believe you want this
Select Col1 + Col2 + Col3 + Col4 + Col5 From Table
Or may be following
Select Col1 From Table1
union Select Col2 From Table1
union Select Col3 From Table1
union Select Col4 From Table1
union Select Col5 From Table1 ;

Resources