Show column names having null values in row - sql

I would like to display only those column name against the student id whose question(q1,q2,q3,q4...etc) value is null below is the printscreen of table against the id i would like to have question id . with below expected o/p

You can use FOR XML to achieve the result:
SQL Fiddle
;WITH Cte AS(
SELECT id, name, q = 'q1' FROM Test WHERE q1 IS NULL UNION ALL
SELECT id, name, q = 'q2' FROM Test WHERE q2 IS NULL UNION ALL
SELECT id, name, q = 'q3' FROM Test WHERE q3 IS NULL UNION ALL
SELECT id, name, q = 'q4' FROM Test WHERE q4 IS NULL UNION ALL
SELECT id, name, q = 'q5' FROM Test WHERE q5 IS NULL UNION ALL
SELECT id, name, q = 'q6' FROM Test WHERE q6 IS NULL
)
SELECT
id,
name,
incompletes = STUFF((
SELECT ',' + c2.q
FROM Cte c2
WHERE
c1.id = c2.id
AND c1.name = c2.name
GROUP BY c2.id, c2.name, c2.q
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
, 1, 1, '')
FROM Cte c1
GROUP BY c1.id, c1.name
ORDER BY c1.id, c1.name

SELECT ID, NAME,
RTRIM ((CASE WHEN Q1 IS NULL THEN 'Q1,' END)||
(CASE WHEN Q2 IS NULL THEN 'Q2,' END)||
(CASE WHEN Q3 IS NULL THEN 'Q3,' END)||
(CASE WHEN Q4 IS NULL THEN 'Q4,' END)||
(CASE WHEN Q5 IS NULL THEN 'Q5,' END)||
(CASE WHEN Q6 IS NULL THEN 'Q6,' END),',') AS NULL_QUESTIONS
FROM TABLE
EDIT: Added STUFF to get rid of the leading comma and added ELSE '':
SELECT ID, NAME,
STUFF (
CASE WHEN Q1 IS NULL THEN ',q1' ELSE '' END +
CASE WHEN Q2 IS NULL THEN ',q2' ELSE '' END +
CASE WHEN Q3 IS NULL THEN ',q3' ELSE '' END +
CASE WHEN Q4 IS NULL THEN ',q4' ELSE '' END +
CASE WHEN Q5 IS NULL THEN ',q5' ELSE '' END +
CASE WHEN Q6 IS NULL THEN ',q6' ELSE '' END
, 1,1,'') AS NULL_QUESTIONS
FROM Test

SELECT Panelist_ID, EmailAddress collate Latin1_General_CI_AI,
STUFF (
CASE WHEN convert (nvarchar (14), PQ_160175) IS NULL THEN ',PQ_160175' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161979) IS NULL THEN ',PQ_161979' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161980) IS NULL THEN ',PQ_161980' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161981) IS NULL THEN ',PQ_161981' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161982) IS NULL THEN ',PQ_161982' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161983) IS NULL THEN ',PQ_161983' ELSE '' END +
CASE WHEN convert (nvarchar (14), PQ_161986) IS NULL THEN ',PQ_161986' ELSE '' END +
CASE WHEN PQ_172469 IS NULL THEN ',PQ_172469' ELSE '' END +
CASE WHEN PQ_180972 IS NULL THEN ',PQ_180972' ELSE '' END +
CASE WHEN PQ_180973 IS NULL THEN ',PQ_180973' ELSE '' END +
CASE WHEN PQ_189924 IS NULL THEN ',PQ_189924' ELSE '' END +
CASE WHEN PQ_195859 IS NULL THEN ',PQ_195859' ELSE '' END +
CASE WHEN PQ_195860 IS NULL THEN ',PQ_195860' ELSE '' END +
CASE WHEN PQ_196605 IS NULL THEN ',PQ_196605' ELSE '' END +
CASE WHEN PQ_196606 IS NULL THEN ',PQ_196606' ELSE '' )
i have been using the aboce case statement and i am not able to see the output after 161983 nos

Related

SQL CONCAT statement with multiple conditions

I have a table with output as of following:
I am trying to concat the outputs into a single output, given the conditions that:
When column fields (Type 1 to Type 5) IS NOT NULL OR '', take the value and combine it with another field with the same condition met
Expected output(based on screenshot above): RAM/TOTAL/N.A.
When column field (Type 6) IS NOT NULL OR '', display the result as OUT OF SERVICE, ignoring other values
Expected output: OUT OF SERVICE
Sample query:
SELECT CONCAT(Type1, '/' , Type2, '/' , Type3, '/' , Type4, '/' , Type5, '/' , Type6) AS OUTPUT FROM #myTable
You example screen shots do not agree with your expected output.
You say if Type6 is Null or blank, then it should say 'OUT OF SERVICE'
However, in your screen shot, your expected output concats the previous columns though Type6 is blank! Should it not say OUT OF SERVICE ??
Assuming that this is simply a typo.. what you could do is the following:
Set the values of the column to null if blank and then concat them in the subsequent select. Just one one many ways to do it..
;with mycte as
(select
'' as Type1
, 'RAM' as Type2
,'' as Type3
,'TOTAL' as Type4
,'N/A' as Type5
,'' as Type6
)
,set_null as (
select
Type1 = case when isnull(Type1,'') = '' then NULL else Type1+'/' end
,Type2 = case when isnull(Type2,'') = '' then NULL else Type2+'/' end
,Type3 = case when isnull(Type3,'') = '' then NULL else Type3 +'/'end
,Type4 = case when isnull(Type4,'') = '' then NULL else Type4+'/' end
,Type5 = case when isnull(Type5,'') = '' then NULL else Type5+'/' end
,Type6 = case when isnull(Type6,'') = '' then NULL else Type6 end
from mycte
)
select
case
when isnull(Type6,'') = '' then 'OUT OF SERVICE'
else concat(Type1+Type2,Type3,Type4,Type5,Type6)
end as concat_column
from set_null
You may try this. This is an approach use to remove unnecessary character added due to no null blank value from a string.
First create your string and remove the duplicate unnecessary / from the string.
At the end only need to check whether / is added in suffix or prefix which need to be removed, by using simple case and substring you can achieve the same.
;with cte as
(select 'sd' as Type1, 'RAM' as Type2,'' as Type3,'TOTAL' as Type4,'N.A' as Type5,null as Type6)
,ct as (
SELECT case when Type6 is null ---- you may chnage your condition of checking Type6 is over there
then 'OUT OF SERVICE'
else REPLACE( REPLACE( CONCAT('][', Type1, '][' , Type2, '][' , Type3, '][' , Type4, '][' , Type5, '][' , Type6), '[]', ''), '][', '/')
End AS OUTP FROM cte
)
select
case when OUTP like '/%'
then case when OUTP like '%/'
then SUBSTRING( OUTP, 2, len(OUTP)-2 )
else SUBSTRING( OUTP, 2, len(OUTP)-1 ) end
else case when OUTP like '%/'
then SUBSTRING( OUTP, 1, len(OUTP)-1 )
else OUTP end
End as OUTPU
from ct

CONCAT with IF condition in SQL Server

I have a table with four columns presenting {YES, NO, N/A} values. What I'd like to obtain is a column with concatenated names of those columns which present a 'YES' value separate by a double underscore.
\, A, B, C, D
1, YES, NO, YES, N/A
2, NO, YES, N/A, N/A
3, YES, NO, NO, YES
Expected result:
A__C
B
A__D
Something like:
select CONCAT(
IF(A = 'YES', 'A'),
IF(B = 'YES', 'B'),
IF(C = 'YES', 'C'),
IF(D = 'YES', 'D'))
from my_table
Hope I understand you right, that you want a double underscore separator.
This solution works without any subquery or cte processing.
select substring(
iif(a='YES','__A','') + iif(b='YES','__B','') +
iif(c='YES','__C','') + iif(d='YES','__D','')
,3,100)
from table1
One should know that this: substring('', 3, 100) will work using SqlServer.
Assuming T1 is your table:
SELECT CASE WHEN LEN(X)>0 THEN LEFT(X, LEN(X)-2) ELSE '' END AS Y
FROM (
SELECT
CASE WHEN A='YES' THEN 'A__' ELSE '' END + CASE WHEN B='YES' THEN 'B__' ELSE '' END + CASE WHEN C='YES' THEN 'C__' ELSE '' END + CASE WHEN D='YES' THEN 'D__' ELSE '' END AS X
FROM T1
) A
WITH ABC
as
(
Select
(
CASE WHEN A = 'YES' THEN 'A_' ELSE '' END as A +
CASE WHEN B = 'YES' THEN 'B_' ELSE '' END as B +
CASE WHEN C = 'YES' THEN 'C_' ELSE '' END as C +
CASE WHEN D = 'YES' THEN 'D_' ELSE '' END as D
) as output
)
Select case when len(output) = 2 then left (output,1)
else output
end as output
From ABC
Select case A then 'YES' then 'A' else '_'end + case B then 'YES' then 'B' else '_'end +case C then 'YES' then 'C' else '_'end +case D then 'YES' then 'D' else '_'end as result from my_table

How to specify multiple values in when using case statement in sql server

I have the following table
Id Number TypeOfChange
1 2X Scope,Cost,Schedule,EVM,PA
2 3x Scope,Cost
Expected output:
Id Number TypeOfChange Scope Cost Schedule EVM PA
1 2X Scope,Cost,Schedule,EVM,PA X X X X X
2 3x Scope,Cost X X
I try the following script but its not working
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN TypeOfChange = 'Scope' THEN 'X'
ELSE '' END,
Cost = CASE
WHEN TypeOfChange = 'Cost' THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN TypeOfChange = 'Schedule' THEN 'X'
ELSE '' END,
EVM = CASE
WHEN TypeOfChange = 'EVM' THEN 'X'
ELSE '' END,
PA = CASE
WHEN TypeOfChange = 'PA' THEN 'X'
ELSE '' END
FROM A
Use Like operator.
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN TypeOfChange Like '%Scope%' THEN 'X'
ELSE '' END,
Cost = CASE
WHEN TypeOfChange Like '%Cost%' THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN TypeOfChange Like '%Schedule%' THEN 'X'
ELSE '' END,
EVM = CASE
WHEN TypeOfChange Like '%EVM%' THEN 'X'
ELSE '' END,
PA = CASE
WHEN TypeOfChange Like '%PA%' THEN 'X'
ELSE '' END
FROM A
Example:
we can try charindex or patindex
SELECT
Id,
Number,
TypeOfChange,
Scope = CASE
WHEN CHARINDEX('Scope',TypeOfChange)>0 THEN 'X'
ELSE '' END,
Cost = CASE
WHEN CHARINDEX('Cost',TypeOfChange)>0 THEN 'X'
ELSE '' END,
Schedule = CASE
WHEN CHARINDEX('Schedule',TypeOfChange)>0 THEN 'X'
ELSE '' END,
EVM = CASE
WHEN CHARINDEX('EVM',TypeOfChange)>0 THEN 'X'
ELSE '' END,
PA = CASE
WHEN CHARINDEX('PA',TypeOfChange)>0 THEN 'X'
ELSE '' END
FROM #AA
output
Id Number TypeOfChange Scope Cost Schedule EVM PA
1 2X Scope,Cost,Schedule,EVM,PA X X X X X
2 3x Scope,Cost X X
If TypeOfChange is a dynamic value, you may want to go the dynamic route.
select * into [T1] from
(values (1, '2X', 'Scope,Cost,Schedule,EVM,PA'), (2, '3x', 'Scope,Cost'), (3, '4x', 'someOtherType')) t(Id, Number, TypeOfChange)
--typeOfChange into column list
Declare #SQL varchar(max) = Stuff((
SELECT distinct ',' + QuoteName(LTRIM(RTRIM(m.n.value('.[1]','varchar(8000)'))))
FROM ( SELECT CAST('<XMLRoot><RowData>' + REPLACE(TypeOfChange,',','</RowData><RowData>') + '</RowData></XMLRoot>' AS XML) AS x
FROM [T1]) t CROSS APPLY x.nodes('/XMLRoot/RowData')m(n)
Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [Id],[Number], [TypeOfChange],' + #SQL + '
From (
SELECT Id, Number, TypeOfChange,
LTRIM(RTRIM(m.n.value(''.[1]'',''varchar(8000)''))) AS [Type], ''X'' as Value
FROM ( SELECT Id, Number, TypeOfChange, CAST(''<XMLRoot><RowData>'' + REPLACE(TypeOfChange,'','',''</RowData><RowData>'') + ''</RowData></XMLRoot>'' AS XML) AS x
FROM [T1]) t CROSS APPLY x.nodes(''/XMLRoot/RowData'')m(n)
) A
Pivot (max(Value) For [Type] in (' + #SQL + ') ) pvt'
Exec(#SQL);
Alternatively you may want to define your Types in a lookup table
select * into [Types] from
(values (1, 'Scope'), (2, 'Cost'), (3, 'Schedule'), (4, 'EVM'), (5, 'PA'), (6, 'someOtherType')) a (Id, TypeOfChange)
Then change the above --typeOfChange into column.. block like this:
--typeOfChange into column list
Declare #SQL varchar(max) = Stuff((
SELECT distinct ',' + QuoteName(TypeOfChange)
FROM [Types]
Order by 1 For XML Path('')),1,1,'')
I think, using LIKE is wrong approach. Especcialy in cases, when one of your strings become f.e."Periscope". You will get false positives.
Try to create user defined function to split strs:
CREATE FUNCTION [dbo].[str__split](
#str NVARCHAR(MAX)
,#delimiter NVARCHAR(MAX)
)
RETURNS #split TABLE(
[str] NVARCHAR(MAX)
)
AS
BEGIN
INSERT INTO #split(
[str]
)
SELECT
[X].[C].[value]('(./text())[1]', 'nvarchar(4000)')
FROM
(
SELECT
[X] = CONVERT(XML, '<i>' + REPLACE(#str, #delimiter, '</i><i>') + '</i>').query('.')
) AS [A]
CROSS APPLY
[X].[nodes]('i') AS [X]([C]);
RETURN;
END
And then use query:
SELECT
[t].*
,[Scope] = CASE WHEN [t2].[Scope] IS NULL THEN NULL ELSE 'X' END
,[Cost] = CASE WHEN [t2].[Cost] IS NULL THEN NULL ELSE 'X' END
,[Schedule] = CASE WHEN [t2].[Schedule] IS NULL THEN NULL ELSE 'X' END
,[EVM] = CASE WHEN [t2].[EVM] IS NULL THEN NULL ELSE 'X' END
,[PA] = CASE WHEN [t2].[PA] IS NULL THEN NULL ELSE 'X' END
FROM
[your table] AS [t]
OUTER APPLY
(
SELECT * FROM (SELECT [str] from [dbo].[str__split]([TypeOfChange], ',')) AS [d]
PIVOT
(MAX([str]) FOR [str] IN ([Scope], [Cost], [Schedule], [EVM], [PA])) AS [piv]
) AS [t2]

SQL - Query to seperate single column and create new columns based on column data

Sorry, if the title is horrible. Have a table T. With a column Name, Num, and Status that either contains a I, O, or S.
Ex:
Name Num Status
Bob 1 I
Bob 2 O
Bob 3 O
John 4 I
John 5 S
Joe 6 O
Want result to look like:
Name Num I O S
Bob 1 x
Bob 2 x
Bob 3 X
John 4 X
John 5 X
Thanks!
Edit: Follow up question.
Name Num I O S
Bob 1 x
Bob 1 x
Bob 2 X
Need result:
Name Num I O S
Bob 1 X X
Bob 2 X
EDIT 2: Actual Query:
SELECT Name, Card_Nmbr,
[Out] = case when d.Status='I' then 'X' else '' end,
[In] = case when d.Status='O' then 'X' else '' end,
[Sales] = case when d.Status='S' then 'X' else '' end
FROM [PCOdb].[dbo].[GC_Header] as h
INNER JOIN GC_Detail as d on h.GC_TransNmbr = d.GC_TransNmbr
INNER JOIN GC_Master as m on d.GCM_Nmbr = m.GCM_Nmbr
INNER JOIN Galaxy1.dbo.GxUsers as u on h.UserID = u.UserID
WHERE GC_TransDate between '11/29/16' and dateadd(day,1, '11/29/16')
Group BY Card_Nmbr, Name
A simple case statement would help here
Select Name
,Num
,[I] = case when [Status]='I' then 'X' else '' end
,[O] = case when [Status]='O' then 'X' else '' end
,[S] = case when [Status]='S' then 'X' else '' end
From YourTable
EDIT to handle multiple rows
Select Name
,Num
,[I] = max(case when [Status]='I' then 'X' else '' end)
,[O] = max(case when [Status]='O' then 'X' else '' end)
,[S] = max(case when [Status]='S' then 'X' else '' end)
From YourTable
Group By Name,Num
Edit 2 - Full Query (Assuming the Joins are doing what you need)
SELECT Name
,Card_Nmbr
,[Out] = max(case when d.[Status]='I' then 'X' else '' end)
,[In] = max(case when d.[Status]='O' then 'X' else '' end)
,[Sales] = max(case when d.[Status]='S' then 'X' else '' end)
FROM [PCOdb].[dbo].[GC_Header] as h
JOIN GC_Detail as d on h.GC_TransNmbr = d.GC_TransNmbr
JOIN GC_Master as m on d.GCM_Nmbr = m.GCM_Nmbr
JOIN Galaxy1.dbo.GxUsers as u on h.UserID = u.UserID
WHERE GC_TransDate between '2016-11-29' and DateAdd(DD,1,'2016-11-29')
Group BY Card_Nmbr, Name
Use Case expression.
Demo:
Create table #temp
(Name varchar (10),
Num int ,
[Status] char(1))
insert into #temp values ('Bob' , '1' , 'I')
insert into #temp values ('Bob' , '2' , 'O')
insert into #temp values ('Bob' , '3' , 'O')
insert into #temp values ('John' , '4' , 'I')
insert into #temp values ('John' , '5' ,'S')
insert into #temp values ('Joe' , '6' , 'O')
select Name,
Num,
[I] = case
when [Status] ='I'
then 'X'
else ''
end
,[O] = case
when [Status] ='O'
then 'X'
else ''
end
,[S] = case when [Status] ='S'
then 'X'
else ''
end
from #temp
drop table #temp
Result:
For SQL Server 2012 and Later you can use IIF (Transact-SQL) function too.
Select Name
,Num
,IIF([Status] = 'I' , 'X', '' ) AS [I]
,IIF([Status] = 'O' , 'X', '' ) AS [O]
,IIF([Status] = 'S' , 'X', '' ) AS [S]
FROM TableName

convert certain column names with comma separated string from sql table with conditions

For example , I have this table with different column names and the Boolean value below it,
case1 case2 case3 case4
1 0 1 0
What I want to retrieve,only column names with 1 value. So, my desired results from the query should only be case1,case3
Desired Output : case1,case3
there is only one row fetch from sql query
Is there any way?
If I understand correctly, you could use a big case statement:
select stuff(( (case when case1 = 1 then ',case1' else '' end) +
(case when case2 = 1 then ',case2' else '' end) +
(case when case3 = 1 then ',case3' else '' end) +
(case when case4 = 1 then ',case4' else '' end)
), 1, 1, '') as columns
In the case you have multiple rows.
Query
select stuff((
(case when count(*) = sum(cast(case1 as int)) then ',case1' else '' end) +
(case when count(*) = sum(cast(case2 as int)) then ',case2' else '' end) +
(case when count(*) = sum(cast(case3 as int)) then ',case3' else '' end) +
(case when count(*) = sum(cast(case4 as int)) then ',case4' else '' end)), 1, 1, '')
as no_zero_columns
from your_table_name;
SQL Fiddle Demo