I have data like below
| Name | Subject | Answer |
|:----------|:----------|:---------------------:|
|Pranesh |Physics |Numerical Problems |
|Pranesh |Physics |Other |
|Pranesh |Chemistry |Understanding Concepts |
|Pranesh |Chemistry |Organic chemistry reactions
|Pranesh |Maths |Lack of understanding |
|Pranesh |Maths |Insufficient practice |
|Pranesh |Maths |Other |
Using this SQL query:
select *
from
(select
l.FullName Name, sq.Title Subject, cAns.Name Answer
from
Answer as sa
left join
Question AS sq on sq.ID = sa.QuestionID
left join
Master as cAns on cAns.ID = sa.AnswerID
left join
Profile as l on l.ID = sa.ProfileID) src
pivot
(max(Answer)
for Subject in ([Physics], [Chemistry], [Maths], [Biology],[ComputerScience], [CommonUnderstanding])) piv;
I am able to get the data as follows
How to concatenate answer column of same subject and display the same like in above screen shot ?
I have concatenated the answer list first per name and subject, then applied pivoting -
declare #temp table (name varchar(100), subject varchar(100), answer varchar(100))
insert into #temp
select 'Pranesh','Physics' ,'Numerical Problems'
union all select 'Pranesh','Physics' ,'Other'
union all select 'Pranesh','Chemistry','Understanding Concepts'
union all select 'Pranesh','Chemistry','Organic chemistry reactions'
union all select 'Pranesh','Maths' ,'Lack of understanding'
union all select 'Pranesh','Maths' ,'Insufficient practice'
union all select 'Pranesh','Maths' ,'Other'
union all select 'Ramesh','Biology' , 'Other'
union all select 'Ramesh','Biology' , 'Science'
;with cte as (select distinct name, subject from #temp)
select * from
(
select
c.name,
c.subject,
answer = stuff((select ',' + answer from #temp t where t.name=c.name and t.subject=c.subject for xml path('')), 1, 1, '')
from cte c
) src
pivot
(
max(answer) for subject in ([Physics], [Chemistry], [Maths], [Biology],[ComputerScience],[CommonUnderstanding])
) piv
Try this:-
SELECT ANS, PHYSICS,CHEMISTRY,MATHS
FROM
(
SELECT L.FULLNAME NAME, SQ.TITLE SUBJECT, CANS.NAME ANSWER FROM ANSWER AS SA
LEFT JOIN QUESTION AS SQ ON SQ.ID = SA.QUESTIONID
LEFT JOIN MASTER AS CANS ON CANS.ID = SA.ANSWERID
LEFT JOIN PROFILE AS L ON L.ID = SA.PROFILEID
) AS T
UNPIVOT
(
COMBINE_COLUMN_VALUES FOR ANS IN (ANSWER)
) AS U
PIVOT
(
MAX(COMBINE_COLUMN_VALUES) FOR [SUBJECT] IN (PHYSICS,CHEMISTRY,MATHS)
) AS P
Related
I want to present multiple rows data for a particular Id in comma separated list. If it has only one join I have no problem to display but when it includes many tables it is not presented properly.
My data is as follows.
Declare #EmpClass Table(ClassId varchar(10),EmpId int)
INSERT INTO #EmpClass
Values('A',1)
,('B',2)
,('C',3)
Declare #Employees Table (EmpId int, EmpName Varchar(100))
INSERT INTO #Employees
VALUES(1,'RAM')
,(2,'RAJ')
,(3,'LAXMAN')
Declare #EmpSubjects Table (EmpId int, SubjectId int)
INSERT INTO #EmpSubjects
VALUES(1,1)
,(1,2)
,(1,3)
,(2,1)
,(3,1)
,(3,2)
Declare #Subjects Table (SubjectId int, Subject Varchar(100))
INSERT INTO #Subjects
VALUES(1,'Maths')
,(2,'Science')
,(3,'Physics')
,(4,'Physics')
,(5,'Maths')
,(6,'Physics')
I have tried the below code and got the below result
SELECT EC.ClassId,E.EmpId
,ES.SubjectId,Subject
FROM #EmpClass EC
LEFT JOIN #Employees E ON EC.EmpId=E.EmpId
LEFT JOIN #EmpSubjects ES ON E.EmpId=ES.EmpId
LEFT JOIN #Subjects S ON S.SubjectId=ES.SubjectId
WHERE E.EmpId=1
I got the below result
ClassId EmpId SubjectId Subject
A 1 1 Maths
A 1 2 Science
A 1 3 Physics
The result needed as follows.
ClassId EmpId SubjectId Subject
A 1 1 {"1":"Maths","2":"Science","3":"Physics"}
I appreciate your help for this.
Thanks
The comma-separated data in your expected result looks like JSON to me. Have you tried something like this?
SELECT EC.ClassId,E.EmpId,
Subject = (
SELECT [1], [2], [3], [4], [5], [6]
FROM (
SELECT S.SubjectID, S.Subject
FROM #EmpSubjects ES
LEFT JOIN #Subjects S ON S.SubjectId=ES.SubjectId
WHERE ES.EmpId=E.EmpId
) as Src
PIVOT (
MAX([Subject])
for [SubjectID] in ([1], [2], [3], [4], [5], [6])
) as p
FOR JSON AUTO, WITHOUT_ARRAY_WRAPPER
)
FROM #EmpClass EC
LEFT JOIN #Employees E ON EC.EmpId=E.EmpId
WHERE E.EmpId=1
Which yields the result:
ClassId EmpId Subject
-------- ------ -----------------------------------------
A 1 {"1":"Maths","2":"Science","3":"Physics"}
With 2014 it's a little bit more of a challange but here's an option using the xml functions:
SELECT [Results].[ClassId]
, [Results].[EmpId]
, '{' + STUFF((SELECT ',"' + CONVERT(VARCHAR(2), tb.[SubjectId]) + '":"' + CAST(tb.[Subject] AS VARCHAR(MAX)) + '"'
FROM (
SELECT [EC].[ClassId]
, [E].[EmpId]
, [ES].[SubjectId]
, [S].[Subject]
FROM #EmpClass [EC]
LEFT JOIN #Employees [E]
ON [EC].[EmpId] = [E].[EmpId]
LEFT JOIN #EmpSubjects [ES]
ON [E].[EmpId] = [ES].[EmpId]
LEFT JOIN #Subjects [S]
ON [S].[SubjectId] = [ES].[SubjectId]
) AS [tb]
WHERE ( [tb].[ClassId] = [Results].[ClassId] AND tb.[EmpId] = [Results].[EmpId] )
FOR XML PATH(''), TYPE
).[value]('(./text())[1]', 'VARCHAR(MAX)'), 1, 1, '') + '}' AS [Subjects]
FROM (
SELECT [EC].[ClassId]
, [E].[EmpId]
, [ES].[SubjectId]
FROM #EmpClass [EC]
LEFT JOIN #Employees [E]
ON [EC].[EmpId] = [E].[EmpId]
LEFT JOIN #EmpSubjects [ES]
ON [E].[EmpId] = [ES].[EmpId]
) [Results]
WHERE [Results].[EmpId] = 1
GROUP BY [Results].[ClassId], [Results].[EmpId]
Giving you the results of:
ClassId EmpId Subjects
---------- ----------- -------------------------------------------
A 1 {"1":"Maths", "2":"Science", "3":"Physics"}
The first sub-query is converting to XML using the FOR XML, so we can basically aggregate the columns. Then STUFF() to remove the leading "," from it. Then wrap that with "{}"
This question already has answers here:
How to concatenate text from multiple rows into a single text string in SQL Server
(47 answers)
Closed 5 years ago.
I'm looking for a way to group whilst also concatenating rows into a comma separated string.
Example:
Name Place
Steve Jones New York
Steve Jones Washington
Albert Smith Miami
Albert Smith Denver
to ...
Steve Jones New York, Washington
Albert Smith Miami, Denver
Greatly appreciated
If you use SQL Server 2008 and above, you can use STUFF and XML PATH to get the result you want.
SELECT DISTINCT Name
, STUFF((
SELECT ',' + Place
FROM YourTable t1
where t1.Name = t2.Name
FOR XML PATH('')
), 1, 1, '') AS Places
FROM YourTable t2
You can use String_Agg if you are using 2017, SQL Azure else you can query as below:
Select [Name],
Places = Stuff((Select ', '+Place from yourtable where [Name] = t.[Name] for xml path('')),1,2,'')
from yourtable
group by [Name]
There's probably a simpler way, but this works:
with N as
(
select name, count(*) over (partition by name order by name) c from PersonPlace
),
Q as
(
select J.name, J.place, cast(J.place as varchar) place_name, J.c cnt, 1 c from
(select distinct(name) from PersonPlace) K
cross apply
(
select top 1 P.*, N.c from PersonPlace P
inner join N on N.name = P.name
where P.name = K.name
) J
union all
select P.name, P.place, cast(Q.place + ', ' + P.place as varchar), Q.cnt, Q.c + 1
from PersonPlace P
inner join Q on Q.name = P.name and Q.c + 1 <= cnt and P.place <> Q.place
)
select Q.name, Q.place_name from Q where Q.c = Q.cnt
Results:
name place_name
-------------- ----------------------
Steve Jones New York, Washington
Albert Smith Denver, Miami
Rextest Demo
If the People and Places are actually separate tables with their own keys, then we can simply quite a bit.
Using CROSS APPLY and FOR XML PATH:
SELECT distinct PP.Name, SUBSTRING(A.Places, 0, LEN(A.Places)) AS CombinedPlaces
FROM PersonPlace PP
CROSS APPLY
(
SELECT place + ', '
FROM PersonPlace AS AP
WHERE AP.Name = PP.Name
FOR XML PATH('')
) A(places)
I have a query with the following result:
query:
SELECT Tasks.TaskId, Comments.Comment, comments.timespent
FROM comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
WHERE ( comments.entity = 1 )
GROUP BY Tasks.TaskId, Comments.Comment, comments.timespent
Result:
TaskID Comment TimeSpent
__________________________
111754 C1 4
111754 C2 1
111754 C3 79
Please tell me how should I write my query to get the result as follows:
TaskID Comment TimeSpent
__________________________________
111754 ,C1,C2,C3 84
Thanks in advance.
Here's the working SQL Fiddle: http://sqlfiddle.com/#!3/3597a/3
Here's the actual working SQL.
SELECT Tasks.TaskId, SUBSTRING(
(SELECT ',' + Comments.Comment
FROM Comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
FOR XML PATH('')),2,200000) AS Comments
, SUM(comments.timespent) AS TimeSpent
FROM comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
WHERE ( comments.entity = 1 )
GROUP BY Tasks.TaskId
Create Table and Populate Data
CREATE TABLE Tasks
(
TaskID NVARCHAR(20) NOT NULL,
);
CREATE TABLE Comments
(
Entity INT NOT NULL,
EntityID NVARCHAR(20) NOT NULL,
Comment NVARCHAR(50) NOT NULL,
TimeSpent INT NOT NULL
);
INSERT INTO Tasks VALUES
( '111754' );
INSERT INTO Comments VALUES
(1,'111754', 'C1',4 ),
(1,'111754', 'C2',1 ),
(1,'111754', 'C3',79 );
Execute SQL
SELECT Tasks.TaskId, SUBSTRING(
(SELECT ',' + Comments.Comment
FROM Comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
FOR XML PATH('')),2,200000) AS Comments
, SUM(comments.timespent) AS TimeSpent
FROM comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
WHERE comments.entity = 1
GROUP BY Tasks.TaskId
View Results.
TASKID COMMENTS TIMESPENT
111754 C1,C2,C3 84
You can do with CROSS APPLY with XML Path such as:
`
Select *
from table1 t1
CROSS APPLY
(
SELECT
[text()] = t.[Name] + '; '
FROM table2 t2
WHERE t1.[Id] = t2.[Id]
ORDER BY t2.name
FOR XML PATH('')
) a (Type)
`
You should look into FOR XML PATH.
Ok, this is a bit more complicated but it doesn't use xml, and it can be used with other databases than sql server:
WITH orig
AS (SELECT 1 AS f1, 'C11' AS f2
UNION ALL
SELECT 1 AS f1, 'C12' AS f2
UNION ALL
SELECT 1 AS f1, 'C13' AS f2
UNION ALL
SELECT 2 AS f1, 'C21' AS f2
UNION ALL
SELECT 2 AS f1, 'C22' AS f2
UNION ALL
SELECT 2 AS f1, 'C23' AS f2
UNION ALL
SELECT 3 AS f1, 'C31' AS f2)
, orig2 AS (SELECT DISTINCT f1, f2 FROM orig)
, orig3 AS (SELECT f1, f2, row_number() OVER(PARTITION BY f1 ORDER BY f2) AS RowNum FROM orig2)
, orig4
-- Use recursion to concatenate the fields
AS (SELECT f1, CONVERT(VARCHAR(MAX), f2) AS val, rownum
FROM orig3
WHERE RowNum = 1
UNION ALL
SELECT orig4.f1, orig4.val + ', ' + orig3.f2 AS val, orig3.rownum
FROM orig4
INNER JOIN orig3
ON orig4.RowNum + 1 = orig3.RowNum
AND orig4.f1 = orig3.f1)
SELECT *
FROM orig4
-- select only the rows that match the maximum rownum
WHERE NOT EXISTS
(SELECT 1
FROM orig4 o44
WHERE o44.f1 = orig4.f1
AND o44.rownum > orig4.rownum)
Another approach that works only for sql server would be to build an aggregate CLR function that concatenates the values: http://msdn.microsoft.com/en-us/library/91e6taax%28v=vs.90%29.aspx.
If you came across this article but you use oracle, you have the option to use the query above or define a custom aggregate function in pl/sql (http://docs.oracle.com/cd/B28359_01/appdev.111/b28425/aggr_functions.htm).
You should use the STRING_AGG function. It is a sql aggregator function for string. Your final query I think will be:
SELECT Tasks.TaskId, STRING_AGG(Comments.Comment, ', '), SUM(comments.timespent)
FROM comments
INNER JOIN tasks ON comments.entityid = tasks.taskid
WHERE ( comments.entity = 1 )
GROUP BY Tasks.TaskId
I have a parents table looks like this
CHILD_ID | PARENT_ID | NAME
1 | Null | Bill
2 | 1 | Jane
3 | 1 | Steve
4 | 2 | Ben
5 | 3 | Andrew
Id like to get a result set like this
Bill
---Jane
------Ben
---Steve
------Andrew
I know I need to do a rank query to rank the levels and a self join but all I can find on the net is CTE recursion
I have done this in Oracle before but not in MS SQL
Bit hacky and can be improved but hopefully it shows the principle...
;with relation (childId, parentId, childName, [level], [orderSequence])
as
(
select childId, parentId, childName, 0, cast(childId as varchar(20))
from #parents
where parentId is null
union all
select p.childId, p.parentId, r.[level]+1, cast(r.orderSequence + '_' + cast(p.childId as varchar) as varchar(20))
from #parents p
inner join relation r on p.parentId = r.childId
)
select right('----------', ([level]*3)) +childName
from relation
order by orderSequence
If however you want to avoid recursion then an alternative approach is to implement a tree table with the relevant tree structure information - see http://www.sqlteam.com/article/more-trees-hierarchies-in-sql for a walk through
declare #pc table(CHILD_ID int, PARENT_ID int, [NAME] varchar(80));
insert into #pc
select 1,NULL,'Bill' union all
select 2,1,'Jane' union all
select 3,1,'Steve' union all
select 4,2,'Ben' union all
select 5,3,'Andrew' union all
select 6,NULL,'Tom' union all
select 7,8,'Dick' union all
select 8,6,'Harry' union all
select 9,3,'Stu' union all
select 10,7,'Joe';
; with r as (
select CHILD_ID, PARENT_ID, [NAME], depth=0, sort=cast(CHILD_ID as varchar(max))
from #pc
where PARENT_ID is null
union all
select pc.CHILD_ID, pc.PARENT_ID, pc.[NAME], depth=r.depth+1, sort=r.sort+cast(pc.CHILD_ID as varchar(30))
from r
inner join #pc pc on r.CHILD_ID=pc.PARENT_ID
where r.depth<32767
)
select tree=replicate('-',r.depth*3)+r.[NAME]
from r
order by sort
option(maxrecursion 32767);
This was a tough one:). I expanded the example to include > 1 tree. Results looking good so far.
WITH DirectReports (ParentUniqId, UniqId, SortID)
AS
(
SELECT e.ParentUniqId, e.UniqId, e.UniqId as SortID
FROM Coding.Coding AS e
WHERE isnull(ParentUniqId ,0)=0
UNION ALL
SELECT e.ParentUniqId, e.UniqId,, d.SortID * 100 + e.UniqId as SortID
FROM Coding.Coding AS e
INNER JOIN DirectReports AS d
ON e.ParentUniqId = d.UniqId
)
SELECT ParentUniqId, Perfix,SortID
FROM DirectReports order by rtrim(SortID) , uniqid
UNPIVOT will not return NULLs, but I need them in a comparison query. I am trying to avoid using ISNULL the following example (Because in the real sql there are over 100 fields):
Select ID, theValue, column_name
From
(select ID,
ISNULL(CAST([TheColumnToCompare] AS VarChar(1000)), '') as TheColumnToCompare
from MyView
where The_Date = '04/30/2009'
) MA
UNPIVOT
(theValue FOR column_name IN
([TheColumnToCompare])
) AS unpvt
Any alternatives?
To preserve NULLs, use CROSS JOIN ... CASE:
select a.ID, b.column_name
, column_value =
case b.column_name
when 'col1' then a.col1
when 'col2' then a.col2
when 'col3' then a.col3
when 'col4' then a.col4
end
from (
select ID, col1, col2, col3, col4
from table1
) a
cross join (
select 'col1' union all
select 'col2' union all
select 'col3' union all
select 'col4'
) b (column_name)
Instead of:
select ID, column_name, column_value
From (
select ID, col1, col2, col3, col4
from table1
) a
unpivot (
column_value FOR column_name IN (
col1, col2, col3, col4)
) b
A text editor with column mode makes such queries easier to write. UltraEdit has it, so does Emacs. In Emacs it's called rectangular edit.
You might need to script it for 100 columns.
It's a real pain. You have to switch them out before the UNPIVOT, because there is no row produced for ISNULL() to operate on - code generation is your friend here.
I have the problem on PIVOT as well. Missing rows turn into NULL, which you have to wrap in ISNULL() all the way across the row if missing values are the same as 0.0 for example.
I ran into the same problem. Using CROSS APPLY (SQL Server 2005 and later) instead of Unpivot solved the problem. I found the solution based on this article An Alternative (Better?) Method to UNPIVOT
and I made the following example to demonstrate that CROSS APPLY will NOT Ignore NULLs like Unpivot.
create table #Orders (OrderDate datetime, product nvarchar(100), ItemsCount float, GrossAmount float, employee nvarchar(100))
insert into #Orders
select getutcdate(),'Windows',10,10.32,'Me'
union
select getutcdate(),'Office',31,21.23,'you'
union
select getutcdate(),'Office',31,55.45,'me'
union
select getutcdate(),'Windows',10,null,'You'
SELECT OrderDate, product,employee,Measure,MeasureType
from #Orders orders
CROSS APPLY (
VALUES ('ItemsCount',ItemsCount),('GrossAmount',GrossAmount)
)
x(MeasureType, Measure)
SELECT OrderDate, product,employee,Measure,MeasureType
from #Orders orders
UNPIVOT
(Measure FOR MeasureType IN
(ItemsCount,GrossAmount)
)AS unpvt;
drop table #Orders
or, in SQLServer 2008 in shorter way:
...
cross join
(values('col1'), ('col2'), ('col3'), ('col4')) column_names(column_name)
Using dynamic SQL and COALESCE, I solved the problem like this:
DECLARE #SQL NVARCHAR(MAX)
DECLARE #cols NVARCHAR(MAX)
DECLARE #dataCols NVARCHAR(MAX)
SELECT
#dataCols = COALESCE(#dataCols + ', ' + 'ISNULL(' + Name + ',0) ' + Name , 'ISNULL(' + Name + ',0) ' + Name )
FROM Metric WITH (NOLOCK)
ORDER BY ID
SELECT
#cols = COALESCE(#cols + ', ' + Name , Name )
FROM Metric WITH (NOLOCK)
ORDER BY ID
SET #SQL = 'SELECT ArchiveID, MetricDate, BoxID, GroupID, ID MetricID, MetricName, Value
FROM
(SELECT ArchiveID, [Date] MetricDate, BoxID, GroupID, ' + #dataCols + '
FROM MetricData WITH (NOLOCK)
INNER JOIN Archive WITH (NOLOCK)
ON ArchiveID = ID
WHERE BoxID = ' + CONVERT(VARCHAR(40), #BoxID) + '
AND GroupID = ' + CONVERT(VARCHAR(40), #GroupID) + ') p
UNPIVOT
(Value FOR MetricName IN
(' + #cols + ')
)AS unpvt
INNER JOIN Metric WITH (NOLOCK)
ON MetricName = Name
ORDER BY MetricID, MetricDate'
EXECUTE( #SQL )
I've found left outer joining the UNPIVOT result to the full list of fields, conveniently pulled from INFORMATION_SCHEMA, to be a practical answer to this problem in some contexts.
-- test data
CREATE TABLE _t1(name varchar(20),object_id varchar(20),principal_id varchar(20),schema_id varchar(20),parent_object_id varchar(20),type varchar(20),type_desc varchar(20),create_date varchar(20),modify_date varchar(20),is_ms_shipped varchar(20),is_published varchar(20),is_schema_published varchar(20))
INSERT INTO _t1 SELECT 'blah1', 3, NULL, 4, 0, 'blah2', 'blah3', '20100402 16:59:23.267', NULL, 1, 0, 0
-- example
select c.COLUMN_NAME, Value
from INFORMATION_SCHEMA.COLUMNS c
left join (
select * from _t1
) q1
unpivot (Value for COLUMN_NAME in (name,object_id,principal_id,schema_id,parent_object_id,type,type_desc,create_date,modify_date,is_ms_shipped,is_published,is_schema_published)
) t on t.COLUMN_NAME = c.COLUMN_NAME
where c.TABLE_NAME = '_t1'
</pre>
output looks like:
+----------------------+-----------------------+
| COLUMN_NAME | Value |
+----------------------+-----------------------+
| name | blah1 |
| object_id | 3 |
| principal_id | NULL | <======
| schema_id | 4 |
| parent_object_id | 0 |
| type | blah2 |
| type_desc | blah3 |
| create_date | 20100402 16:59:23.26 |
| modify_date | NULL | <======
| is_ms_shipped | 1 |
| is_published | 0 |
| is_schema_published | 0 |
+----------------------+-----------------------+
Writing in May'22 with testing it on AWS Redshift.
You can use a with clause where you can coalesce the columns where nulls are expected. Alternatively, you can use coalesce in the select statement prior to the UNPIVOT block.
And don't forget to alias with the original column name (Not following won't break or violate the rule but would save some time for coffee).
Select ID, theValue, column_name
From
(select ID,
coalesce(CAST([TheColumnToCompare] AS VarChar(1000)), '') as TheColumnToCompare
from MyView
where The_Date = '04/30/2009'
) MA
UNPIVOT
(theValue FOR column_name IN
([TheColumnToCompare])
) AS unpvt
OR
WITH TEMP1 as (
select ID,
coalesce(CAST([TheColumnToCompare] AS VarChar(1000)), '') as TheColumnToCompare
from MyView
where The_Date = '04/30/2009'
)
Select ID, theValue, column_name
From
(select ID, TheColumnToCompare
from MyView
where The_Date = '04/30/2009'
) MA
UNPIVOT
(theValue FOR column_name IN
([TheColumnToCompare])
) AS unpvt
I had your same problem and this is
my quick and dirty solution :
your query :
select
Month,Name,value
from TableName
unpivot
(
Value for Name in (Col_1,Col_2,Col_3,Col_4,Col_5
)
) u
replace with :
select Month,Name,value from
( select
isnull(Month,'no-data') as Month,
isnull(Name,'no-data') as Name,
isnull(value,'no-data') as value from TableName
) as T1
unpivot
(
Value
for Name in (Col_1,Col_2,Col_3,Col_4,Col_5)
) u
ok the null value is replaced with a string, but all rows will be returned !!
ISNULL is half the answer. Use NULLIF to translate back to NULL. E.g.
DECLARE #temp TABLE(
Foo varchar(50),
Bar varchar(50) NULL
);
INSERT INTO #temp( Foo,Bar )VALUES( 'licious',NULL );
SELECT * FROM #temp;
SELECT
Col,
NULLIF( Val,'0Null' ) AS Val
FROM(
SELECT
Foo,
ISNULL( Bar,'0Null' ) AS Bar
FROM
#temp
) AS t
UNPIVOT(
Val FOR Col IN(
Foo,
Bar
)
) up;
Here I use "0Null" as my intermediate value. You can use anything you like. However, you risk collision with user input if you choose something real-world like "Null". Garbage works fine "!##34())0" but may be more confusing to future coders. I am sure you get the picture.