Multi Column to One Column - sql-server

I am writing a trigger and I am using inserted
Inserted is a single row
like
ColumnX |ColumnY|ColumnZ|
=========================
A | B |C |
I want to insert results to another table like this
ColumnName |Value|
==================
ColumnX | A |
ColumnY | B |
ColumnZ | C |
I have a lot of tables how can I make this?

UNPIVOT the result set, then insert them:
INSERT INTO Anothertable(Columnname, value)
SELECT Columnname, value
FROM tablename t
UNPIVOT
(
value
FOR ColumnName IN(ColumnX, ColumnY, ColumnZ)
) AS u;
SQL Fiddle Demo
To do this dymaincally:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
select #cols = STUFF((SELECT distinct ',' +
QUOTENAME(Columnname)
FROM table1 t
UNPIVOT
(
value
FOR ColumnName IN(ColumnX, ColumnY, ColumnZ)
) AS u
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '');
SET #query = 'SELECT Columnname, value
FROM table1 t
UNPIVOT
(
value
FOR ColumnName IN( ' + #cols + ' )
) AS u;'
execute(#query);
Updated SQL Fiddle Demo

CREATE TRIGGER TriggerName
ON YourDatabase.TableName
AFTER INSERT
AS
BEGIN
INSERT INTO OtherTable (ColumnX, ColumnY, ColumnZ)
SELECT ColumnX, ColumnY, ColumnZ
FROM inserted
END
GO

Related

Use SELECT Result As Column Names

Morning all, Longtime lurker, first time poster.
I'm writing a stored procedure to take the results from one SELECT statement and use that output to build another SELECT statement. Trouble is I can not find a mechanism or code to accomplish this. Assigning the results to a variable doesn't seem to be an option because SQL doesn't support Arrays (that I know of).
+----+-------------+-------------+
| ID | ___$seqval | Column_Name |
+----+-------------+-------------+
| 1 | 0x000000E10 | EnvType |
| 2 | 0x000000E10 | DataType |
| 3 | 0x000000E10 | DateMod |
+----+-------------+-------------+
Trying to get to;
SELECT Column_name(1), Column_name(2)..
From tblServer_Data
There could be up to a total of 20 columns returned.
SQL DEMO
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME([Column_Name])
FROM Table1 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols as Columns; -- just for debug
set #query = 'SELECT [ID], ' + #cols + ' from
(
select 1 as ID
, [seqval]
, [Column_Name]
from Table1
) x
pivot
(
max([seqval])
for [Column_Name] in (' + #cols + ')
) p '
SELECT #query as Query; -- just for debug
execute(#query);
OUTPUT
Then you can do SELECT over that output
This will give a SELECT statement of the columns in a selected table.
SELECT 'SELECT ' + STUFF(
(SELECT ',' + c.column_name from
(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = your_table) c
for xml path ('')),1,1,'') + ' FROM ' + your_table

How to use stuff on entire columns of the table:

I executed the below query and it executed well :-
SELECT table2id, stuff((select CHAR(13) + table1name from table1 where table1id=table2.table2id FOR XML PATH (''), TYPE
).value('.', 'varchar(max)')
, 1, 1, '')
from table2 where table2id=117 group by id;
But when I am using count(*) , like in below query :-
SELECT table2id, stuff((select CHAR(13) + count(*) from table1 where table1id=table2.table2id FOR XML PATH (''), TYPE
).value('.', 'varchar(max)')
, 1, 1, '')
from table2 where table2id=117 group by id;
I am getting the below error:
Msg 245, Level 16, State 1, Line 19
Conversion failed when converting the varchar value '
' to data type int.
Now how can I stuff all the columns in table1 ? could anyone help !
I want my result like below:-
table2id | table1name | table1id | table1color
------------------------------------------------------
117 | jon, jack | 117,117 | blue,red
( I am adding my sample data for table1 and table2) :-
table1:
table1id | table1name | table1color | table1city | table1animal |...(I
have 25 columns like this !)
--------------------------------------------------------------
117 | jon | blue | city1 | animal1
117 | jack | red | city2 | animal2
table2:
table2id | table2uniqueid
-------------------------
117 | asbn6383hhh3j3837
118 | kf9s8sujfu6df5d7j
This has nothing to do with stuff.
The reason you get the error is this:
count(*) returns an int. char(13) is a char. Whenever you try to do int + char SQL Server will try to implicitly convert the char to an int. Naturally, char(13) cannot be converted to an int.
What you need to to explicitly convert the count(*) to varchar:
SELECT table2id, stuff(
(
select CHAR(13) + cast(count(*) as varchar(10))
from table1
where table1id=table2.table2id
FOR XML PATH (''), TYPE).value('.', 'varchar(max)'), 1, 1, '')
from table2
where table2id=117
group by id;
Try this code it will helps you by using Dynamic Sql
Firstly i created Two physical Tables with sample data
CREATE TABLE Table1 (table1id INT , table1name Varchar(100) , table1color Varchar(100) , table1city Varchar(100) , table1animal Varchar(100))
INSERT INTO Table1
SELECT 117, 'jon' , 'blue' , 'city1' , 'animal1' UNION ALL
SELECT 117, 'jack', 'red' , 'city2' , 'animal2'
CREATE TABLE Table2( table2id INT, table2uniqueid nvarchar(1000))
INSERT INTO Table2
SELECT 117,'asbn6383hhh3j3837' Union all
SELECT 118,'kf9s8sujfu6df5d7j'
Dynamic Sql code to get the expected result
SET NOCOUNT ON
IF OBJECT_ID('Tempdb..#TEMP') IS NOT NULL
DROP TABLE #TEMP
CREATE TABLE #TEMP(ID INT IDENTITY ,Query nvarchar(max))
IF OBJECT_ID('Tempdb..#TEMP2') IS NOT NULL
DROP TABLE #TEMP2
CREATE TABLE #TEMP2(ID INT IDENTITY ,Query nvarchar(max))
DECLARE #MinID INT,
#MaxID INT,
#Sql nvarchar(max),
#Getcolumn nvarchar(max),
#Sql2 nvarchar(max),
#CteSql nvarchar(max),
#CteSql2 nvarchar(max),
#FullSql nvarchar(max)
DEClare #COlumn Table
(
ID INT IDENTITY,
COlumnname varchar(100)
)
INSERT into #COlumn(COlumnname)
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME='Table1'
SELECT #MinID=MIn(Id),#MaxID=MAX(ID)FRom #COlumn
While (#MinID <=#MaxID)
Begin
SELECT #Getcolumn=COlumnname From #COlumn WHERE ID=#MinID
SET #Sql=N' STUFF((SELECT '', ''+ CAST('+#Getcolumn +' AS VARCHAR(5))
FROM cte AS i
WHERE i.table1id=o.table1id For XML PATH ('''')),1,1,'''') AS '+#Getcolumn
INSERT INTO #TEMP(Query)
SELECT #Sql
SET #MinID=#MinID+1
END
SELECT DISTINCT #Sql2=
STUFF((SELECT ', '+ CAST(Query AS nvarchar(max)) FROM #TEMP i For Xml Path(''), type
).value('.', 'nvarchar(max)')
, 1, 2, '')
FROM #TEMP o
SET #Sql2=#Sql2 +' FRom Cte o'
SET #CteSql= 'SELECT Top 1 '+''' ;With cte
AS
(SELECT T2.table2id,''+ STUFF((SELECT '', ''+''T1.''+COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
Where TABLE_NAME=''Table1'' For XML PATH ('''')),1,1,'''') +'' From Table2 T2
LEFT JOIN Table1 T1
On T1.table1id=t2.table2id )''' +'+CHAR(13)+CHAR(10)+'+'''SELECT DISTINCT table2id,''
FROM INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME=''Table1'''
INSERT INTO #TEMP2(Query)
EXECUTE(#CteSql)
SELECT #CteSql2= Query From #TEMP2
SET #FullSql=#CteSql2+#Sql2
PRINT #FullSql
EXEC(#FullSql)
SET NOCOUNT OFF
Result After Running the Query
table2id table1id table1name table1color table1city table1animal
---------------------------------------------------------------------------------------
117 117, 117 jon, jack blue, red city1, city2 anima, anima
118 NULL NULL NULL NULL NULL

Create embedded column xml with a sql query

I have a table with below records in it.
+------------+---------+
| State |Strength |
+------------+---------+
| AR | 10000 |
| AK | 20000 |
+------------+---------+
I want to general xml in the below format
<Fields><AR>10000</AR><AK>20000</AK></Fields>
What I've tried so far.
SELECT '<'+State+'>' + Strength+'</'+State+'>'
FROM tbl
FOR XML PATH (''), ROOT('Fields')
Result I get - <Fields><AR>10000</AR><AK>20000</AK></Fields>
You should use type for xml path and value method
DECLARE #SampleData AS TABLE (State varchar(20), Strength int)
INSERT INTO #SampleData
VALUES ('AR', 10000), ('AK', 20000) ,('MP', 30000)
SELECT (SELECT CONCAT('<',sd.State,'>', sd.Strength, '</',sd.State, '>')
FROM #SampleData sd
FOR XML PATH(''), TYPE).value('.[1]', 'nvarchar(max)')
Reference link: Type for xml sql
Or simple query like that
DECLARE #SampleData AS TABLE (State varchar(20), Strength int)
INSERT INTO #SampleData
VALUES ('AR', 10000), ('AK', 20000) ,('MP', 30000)
DECLARE #xml nvarchar(max) = N'<Fields>'
SELECT #xml += CONCAT('<',sd.State,'>', sd.Strength, '</',sd.State, '>')
FROM #SampleData sd
SET #xml += N'</ Fields>'
SELECT #xml
TriV's would be my first choice (already +1)
But, another option (just for fun) is via a PIVOT ... dynamic or not
Dynamic
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName([State]) From tbl Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select *
From (
Select *
From (
Select Col=[State]
,Val=[Strength]
From tbl
) A
Pivot (max([Val]) For [Col] in ('+#SQL+') )p
) A
for XML Path(''''),Root(''Fields'')
'
Exec(#SQL)
Static
Select *
From (
Select *
From (
Select Col=[State]
,Val=[Strength]
From tbl
) A
Pivot (max([Val]) For [Col] in ([AK],[AR]) )p
) A
for XML Path(''),Root('Fields')
Both Return
<Fields>
<AK>20000</AK>
<AR>10000</AR>
</Fields>

T-SQL query on dynamic field with pivot

i have 3 table PhoneBook, DynamicField, PhoneBook_DynamicField_Rel
PhoneBook :
|---ID----|---Name----|
1 Reza
2 Ali
DynamicField :
|---ID----|--Caption--|
1 Job
2 Level
PhoneBook_DynamicField_Rel:
|---ID----|--PhoneBookID--|--DynamicFieldID--|---Value---|
1 1 1 Emp
2 1 2 1
3 2 1 SomeJob
i want execute query with this result :
|--PhoneBookID--|--Name--|--Job--|--Level--|
1 Reza Emp 1
2 Ali SomeJob NULL
Maybe something like this:
Test data:
CREATE TABLE #PhoneBook(ID INT,Name VARCHAR(100))
INSERT INTO #PhoneBook VALUES(1,'Reza'),(2,'Ali')
CREATE TABLE #DynamicField(ID INT,Caption VARCHAR(100))
INSERT INTO #DynamicField VALUES(1,'Job'),(2,'Level')
CREATE TABLE #PhoneBook_DynamicField_Rel(ID INT,PhoneBookID INT,
DynamicFieldID INT,Value VARCHAR(100))
INSERT INTO #PhoneBook_DynamicField_Rel
VALUES(1,1,1,'Emp'),(2,1,2,'1'),(3,2,1,'SomeJob')
Getting the colums
DECLARE #cols VARCHAR(MAX)
SELECT #cols=STUFF
(
(
SELECT
',' +QUOTENAME(tbl.Caption)
FROM
#DynamicField AS tbl
FOR XML PATH('')
)
,1,1,'')
Then the query like this:
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
*
FROM
(
SELECT
PhoneBook.ID,
PhoneBook.Name,
field.Caption,
rel.Value
FROM
#PhoneBook AS PhoneBook
JOIN #PhoneBook_DynamicField_Rel AS rel
ON PhoneBook.ID = rel.PhoneBookID
JOIN #DynamicField AS field
ON rel.DynamicFieldID=field.ID
) AS SourceTable
) AS p
PIVOT
(
MAX(Value) FOR Caption IN('+#cols+')
) AS pvt'
EXECUTE(#query)
Then in my case I will drop the temp tables:
DROP TABLE #PhoneBook
DROP TABLE #DynamicField
DROP TABLE #PhoneBook_DynamicField_Rel
What you need is dynamic pivot:
declare #collist nvarchar(max)
SET #collist = stuff((select distinct ',' + QUOTENAME(caption)
FROM DynamicField
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
declare #q nvarchar(max)
set #q = '
select PhoneBookID, Name, ' + #collist + '
from (
select PhoneBookID, Name, Caption, Value
from (
select PhoneBookID, Name, Caption, Value
from PhoneBook pb
inner join PhoneBook_DynamicField_Rel pbdf on pb.ID = pbdf.PhoneBookID
inner join DynamicField df on df.ID = pbdf.DynamicFieldID
) as x
) as source
pivot (
max(Value)
for caption in (' + #collist + ')
) as pvt
'
exec (#q)

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