I have a table Table which have some columns and I want to convert column values as columns for another table.
I am attaching one screen shot of my requirement.
The upper table is my main table say Table1 and the below is my required table.
Thanks
Whilst the suggested duplicate will get you part of the way there, you actually need to unpivot then pivot, like this.
(Oh and please don't post images. DDL is appreciated and saves us typing and/or guessing.)
CREATE TABLE #Test( Action char, [Key] INT, Old varchar(5), OldValue varchar(5), New varchar(5), NewValue varchar(5));
INSERT INTO #Test VALUES
('U', 123, 'Col1','Dog','Col1','Dog'),
('U', 123, 'Col2','Cat','Col2','Mouse'),
('U', 123, 'Col3','Honey','Col3','Bee'),
('I', 123, NULL,NULL,'Col45','Sun');
SELECT PVT.Action
,PVT.[Key]
,PVT.OldCol1
,PVT.OldCol2
,PVT.OldCol3
,PVT.NewCol1
,PVT.NewCol2
,PVT.NewCol3
,PVT.NewCol45 FROM (
SELECT [Action]
,[Key]
,Label
,Value
FROM #Test
CROSS APPLY (VALUES ('Old'+Old, OldValue), ('New'+New, NewValue)) c(label, value)
)src
PIVOT
(
MAX(VALUE) FOR Label IN (OldCol1, NewCol1, OldCol2, NewCol2, OldCol3, NewCol3, NewCol45)
)PVT
ORDER BY PVT.Action Desc
Action Key OldCol1 OldCol2 OldCol3 NewCol1 NewCol2 NewCol3 NewCol45
------ ----------- ------- ------- ------- ------- ------- ------- --------
U 123 Dog Cat Honey Dog Mouse Bee NULL
I 123 NULL NULL NULL NULL NULL NULL Sun
(2 row(s) affected)
I guess pivoting will be enough:
SELECT *
FROM (
SELECT [Action], [Key], 'Old' + Old as [a], OldValue as [Value]
FROM Table1
UNION ALL
SELECT [Action], [Key], 'New' + New, NewValue
FROM Table1
) as p
PIVOT (
MAX([Value]) FOR [a] IN ([OldCol1],[OldCol2],[OldCol3],[NewCol1],[NewCol2],[NewCol3],[NewCol45])
) as pvt
Output:
Action Key OldCol1 OldCol2 OldCol3 NewCol1 NewCol2 NewCol3 NewCol45
I 123 NULL NULL NULL NULL NULL NULL Sun
U 123 Dog Cat Honey Dog Mouse Bee NULL
If there are MANY Old and 'New` values then you need dynamic SQL
Related
I have a table candidate
id candidate_name
---------------------------
1 john
2 mary
and another table units
id name
--------
1 unit1
2 unit2
3 unit3
i would like to generate an output as
id candidate_name unit1 unit2 unit3
---------------------------------------
1 john null null null
2 mary null null null
Any way I can achieve this?
your data
CREATE TABLE candidate(
id int NOT NULL
,candidate_name VARCHAR(40)
);
INSERT INTO candidate
(id,candidate_name) VALUES
(1,'john'),
(2,'mary');
CREATE TABLE units(
id int NOT NULL
,name VARCHAR(50)
);
INSERT INTO units
(id,name) VALUES
(1,'unit1'),
(2,'unit2'),
(3,'unit3');
you should use Cross Join and Pivot
select
*
from
(
select
c.id,
candidate_name,
cast(null as int) id1,
name
from
candidate c
CROSS JOIN units u
) src pivot (
max(id1) for name in ([unit1], [unit2], [unit3])
) piv;
using Dynamic Sql
DECLARE #SQL nvarchar(max);
DECLARE #names nvarchar(1000)= (
SELECT STRING_AGG(concat('[',name,']'),',')
WITHIN GROUP (order by id) from units)
set #SQL='select
*
from
(
select
c.id,
candidate_name,
cast(null as int) id1,
name
from
candidate c
CROSS JOIN units u
) src pivot (
max(id1) for name in ('+ #names +' )
) piv;'
exec(#SQL)
dbfiddle
I have a single row query returning data in this format:
Col1 Col2 Col3 Col4
-----------------------------
1425 3454 2345 3243
I want it to display it in this format:
Col1 | 1425
Col2 | 3454
Col3 | 2345
Col4 | 3243
How can I do it?
I am avoiding to use UNION method since the above table is extracted from a query and for each <table_name> I would have to paste the table query which will make the process slow.
If the number of fields per table is always constant, then it might work like this.
DECLARE #Table TABLE(
[Col1] int,
[Col2] int,
[Col3] int,
[Col4] int
)
INSERT INTO #Table VALUES(1425, 3454, 2345, 3243); -- some Test data
SELECT * FROM #Table; -- row
SELECT
p.[Columns],
p.[Value]
FROM (
SELECT
[Col1],
[Col2],
[Col3],
[Col4]
FROM #Table
) x
UNPIVOT(
[Value] FOR [Columns] IN ([Col1],[Col2],[Col3],[Col4]) --
) AS P;
You can cross join your query with the column names in order to show the column values in separate rows:
select
columns.col,
case columns.col
when 'Col1' then q.col1
when 'Col2' then q.col2
when 'Col3' then q.col3
when 'Col4' then q.col4
end as value
from ( <your query here> ) q
cross join ( values ('Col1'), ('Col2'), ('Col3'), ('Col4') ) as columns(col);
I'm trying to create some reports for auditing, but I have a very specific question.
There's about 120 columns, each with a specific numeric answer. I'd like to return the column name and the value of the rows of that column. I'm aware I'll get a lot of results, but it's not a problem.
For example I have:
KEY |ColumnA | ColumnB
1 |Value A | ValueB
2 |ValueA2 | ValueB2
But want I want is:
1 |ColumnA | Value A
2 |ColumnA | Value A2
1 |ColumnB | Value B
2 |ColumnB | Value B2
I've tried returning all rows and then joining on itself, but it didn't provide me with the output I needed.
Simple unpivot will do the work :)
declare #tbl table ([Key] int, ColumnA varchar(15), ColumnB varchar(15));
insert into #tbl values
(1, 'Value A', 'ValueB'),
(2, 'ValueA2', 'ValueB2');
select [key], [column], [value] from
(select * from #tbl) p
unpivot
([value] for [column] in (ColumnA, ColumnB)) u
order by [column]
it's so simple...If you know the column names, you could use a simple UNION
SELECT * FROM tblAuditing
SELECT 'ColumnA' AS ColumnA,'ColumnB' AS ColumnA UNION
SELECT ColumnA AS ColumnA,ColumnB AS ColumnA FROM tblAuditing
The following query should do what you want - you need to do a customized sorting for the columns names:
CREATE TABLE #temp (ColumnA VARCHAR(20), ColumnB VARCHAR(20))
INSERT INTO #temp VALUES ('Value A','Value B'),('Value A2','Value B2')
SELECT t.Col, t.Val
FROM (SELECT *,ROW_NUMBER() OVER (ORDER BY (SELECT 1)) RNO FROM #temp t) tmp
CROSS APPLY (VALUES (tmp.ColumnA,'ColumnA',tmp.RNO),(tmp.ColumnB,'ColumnB',tmp.RNO)) AS T(Val,Col,sort)
ORDER BY T.Col, Sort
The result is as below,
Col Val
ColumnA Value A
ColumnA Value A2
ColumnB Value B
ColumnB Value B2
I have a table T :
CREATE TABLE T
(
id INT,
type VARCHAR(200),
type_value VARCHAR(10),
value VARCHAR(200)
);
INSERT INTO T VALUES (1, 'RoomColor', 'room1', 'yellow');
INSERT INTO T VALUES (1, 'RoomColor', 'room2', 'red');
INSERT INTO T VALUES (2, 'RoomColor', 'room1', 'blue');
INSERT INTO T VALUES (2, 'RoomColor', 'room1', 'pink');
INSERT INTO T VALUES (3, 'RoomColor', 'room1', 'white');
INSERT INTO T VALUES (3, 'RoomColor', 'room2', 'grey');
INSERT INTO T VALUES (3, 'RoomColor', 'room2', 'brown');
INSERT INTO T VALUES (4, 'RoomColor', 'room3', 'green');
I need to transform it into :
id BedRoomColor DiningRoomColor
-------------------------------------------
1 yellow red
2 blue pink
3 white grey
4 green null
Logic behind the transformation:
If there are more than two room type_value then discard the third room type_value
For same id if there are more than one room type_value ( for example room1,room1 or room2,room2 or room1,room2) then use first type_value to create as BedRoomColor and second type_value to create DiningRoomColor
If there is only 1 room type_value (for eg. room1 or room2 or room3) for an id then corresponding value ( red,green,yellow etc ) will be placed in BedRoomColor and DiningRoomColor will be null
I am struggling with this logic for couple of days. Can anyone please help me.
Thanks
You can use this script
;WITH CTE AS (
SELECT *, RN = ROW_NUMBER() OVER(PARTITION BY id ORDER BY type_value) FROM T
)
SELECT id, [1] BedRoomColor, [2] DiningRoomColor FROM
(SELECT id,value, RN FROM CTE ) SRC
PIVOT (MAX(value) FOR RN IN ([1], [2]) ) AS PVT
Result:
id BedRoomColor DiningRoomColor
----------- ------------------ ---------------
1 yellow red
2 blue pink
3 white grey
4 green NULL
Another way and with adding type to query is:
;with tt as (
select *,
row_number() over (partition by [type], id order by type_value) rn
-- ^^^^^^ I add type to support other types if there is
from t
)
select id,
max(case when [type] = 'RoomColor' and rn = 1 then [value] end) 'BedRoomColor',
max(case when [type] = 'RoomColor' and rn = 2 then [value] end) 'DiningRoomColor'
from tt
group by id;
SQL Server Fiddle Demo
try this:
with tmp as (
select T.*, rownumber() over(patition by id order by type_value) rang
from T
)
select f1.id, f1.value as BedRoomColor, f2.value as DiningRoomColor
from tmp f1
left outer join tmp f2 on f1.id=f2.id and f2.rang=2
where f1.rang=1
Edit :- for any one with a similar problem, there's a good article covering various solutions here
Given the following tables recs and audit, how would one in SQL transform into the resultant table.
A little background, the former table is a simplified example of an standard SQL table used in a CRUD application collecting data. On any update to a column a record is written to an audit table in EAV form. There is now a requirement to transform the recs table into a historical table with a copy of each row as it was at a point in time for reporting (the data will be stored in a star schema data warehouse ultimately.
It seems like this would be straightforward enough in a procedural language and manageable (if ugly) using cursors, but is there a set based approach that would work?
I'm using T-SQL right now, but I imagine that I could port any examples or ideas from any sufficiently rich SQL dialect.
Setup
create table recs
(
ID int identity(1,1) not null primary key,
Column1 nvarchar(30) not null,
Column2 nvarchar(30) not null,
sys_updated_on datetime not null
)
create table audit
(
ID int identity(1,1) not null primary key,
recs_id int not null,
fieldname nvarchar(30) not null,
old_value nvarchar(30) not null,
new_value nvarchar(30) not null,
sys_updated_on datetime not null
)
insert into recs (Column1, Column2, sys_updated_on)
values ('A', 'B', '2012-10-31 22:00')
, ('C', 'D', '2012-10-31 22:30')
insert into audit (recs_id, fieldname, old_value, new_value, sys_updated_on)
values (1, 'Column1', 'Z', 'A', '2012-10-31 22:00')
, (2, 'Column2','X', 'D', '2012-10-31 22:30')
, (1, 'Column1', 'Y', 'Z', '2012-10-31 21:00')
Resultant Data
Recs
ID Column1 Column2 sys_updated_on
1 A B 31/10/2012 22:00:00
2 C D 31/10/2012 22:30:00
Audit
ID recs_id fieldname old_value new_value sys_updated_on
1 1 Column1 Z A 31/10/2012 22:00:00
2 2 Column2 X D 31/10/2012 22:30:00
3 1 Column1 Y Z 31/10/2012 21:00:00
Desired result
recs_id sys_updated_on Column1 Column2
1 null Y B
1 31/10/2012 21:00:00 Z B
1 31/10/2012 22:00:00 A B
2 null C X
2 31/10/2012 22:30:00 C D
Interesting....
Try this
;with cte as
(
select recs_id, sys_updated_on, column1, column2,
ROW_NUMBER() over (order by sys_updated_on) rn
from audit a
pivot
(max(old_value) for fieldname in (column1,column2)) p
)
select
recs_id,
case when ud1>ud2 then ud1 else ud2 end as updateddate,
coalesce(cte.column1,mc1,recs.column1),
coalesce(cte.column2,mc2,recs.column2)
from cte
outer apply
(
select top 1
column1 as mc1, sys_updated_on as ud1
from cte prev1
where prev1.recs_id=cte.recs_id and prev1.rn<cte.rn
order by prev1.rn desc
) r1
outer apply
(
select top 1
column2 as mc2, sys_updated_on as ud2
from cte prev2
where prev2.recs_id=cte.recs_id and prev2.rn<cte.rn
order by prev2.rn desc
) r2
inner join recs on cte.recs_id = recs.id
where cte.sys_updated_on is not null
union
select id, sys_updated_on, Column1, Column2 from recs
order by recs_id, cte.updateddate