MS sql combine columns in select - sql

I am trying to combine multiple columns (varchar, but used to store boolean 'Y' or '') into a single column (list) with human readable text.
The Table layout is like this:
MEMBER_ID (int) | PROC (varchar) | 50K_12_MTHS (varchar) | 100K_12_MTHS (varchar)
1||||
2|Y|Y||
3|Y|Y|Y|
4|Y|||
For the output of the able sample I am trying to get:
1|
2|Proc, 50
3|Proc, 50, 100
4|Proc
I think the way to do this is with a Case (see below) but can't get it to work.
SELECT
MEMBER_ID,
Gorup =
Select(
CASE PROC
WHEN 'Y'
THEN 'Proc'
END + ', ' +
CASE 50K_12_MTHS
WHEN 'Y'
THEN '50K'
END-- + ', ' +
CASE 100K_12_MTHS
WHEN 'Y'
THEN '100K'
END + ', ' +)
from Members

Nearly...!
SELECT
MEMBER_ID,
CASE [PROC]
WHEN 'Y' THEN 'Proc, '
ELSE ''
END +
CASE [50K_12_MTHS]
WHEN 'Y' THEN '50K,'
ELSE ''
END +
CASE [100K_12_MTH]
WHEN 'Y' THEN '100K, '
ELSE ''
END as [group]
from Members

Try this
SELECT
MEMBER_ID,
(CASE [PROC] WHEN 'Y'
THEN 'Proc' ELSE ''
END +
CASE [50K_12_MTHS] WHEN 'Y'
THEN ', 50K' ELSE '' END
+ CASE [100K_12_MTHS] WHEN 'Y'
THEN ', 100K' ELSE ''
END) as [GROUP]
from Members

Related

How to use Case statement in SQL correctly

The below Select statement does NOT return a record for me:
Select 1:
SELECT
Case When rcdr.PolicyNumber like '' + bmpd.PaymentReferenceNumber + '%'
Then 'Adc' else 'Exceed' end as System
FROM RcDetailRecords rcdr
join Bil_ManualPaymentDetails bmpd
on rcdr.PolicyNumber like '' + bmpd.PaymentReferenceNumber + '%' + ''
Output:
System =
The below Select statement DOES return a record for me:
Select 2:
SELECT
Case When rcdr.PolicyNumber like '1234567890%'
Then 'Adc' else 'Exceed' end as System
FROM RcDetailRecords rcdr
join BilManualPaymentDetails bmpd
on rcdr.PolicyNumber like '1234567890%'
Output:
System = Adc
Am I missing a tick '' mark somewhere in the first Select ?
BilManualPaymentDetails Table:
PaymentReferenceNumber
123456789020161013025120
RcDetailRecords Table:
PolicyNumber
1234567890
1234567890 is not like 123456789020161013025120%, but 123456789020161013025120 is like 1234567890%
So it appears you have the fields switched, try:
SELECT
CASE WHEN bmpd.PaymentReferenceNumber LIKE '' + rcdr.PolicyNumber + '%'
THEN 'Adc'
ELSE 'Exceed'
END as System
FROM RcDetailRecords rcdr
JOIN Bil_ManualPaymentDetails bmpd
ON bmpd.PaymentReferenceNumber like '' + rcdr.PolicyNumber + '%' + ''

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]

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

Fill Variable with Case Statement Results

I have a questionnaire that my users have filled out (several thousand a day)
The result is each questionnaire record contains 70 something fields (that correspond to each question)
I've been asked to identify all the affirmatives for each of the 70 questions and concatentate them into one field (a summary of all the issues identified for that record).
In other languages (VBA in particular) I would accomlish this by initializing a variable to '', looping through my recordset and setting the variable to what it was previously + the field name of the issue. I'm not sure how to accomplish this in sql.
I've tried...
DECLARE #strFYI AS NVARCHAR
SET #strFYI = ''
SELECT
a.record_num
,CASE
WHEN a.Date_Missing = 'Yes' THEN #strFYI = #strFYI + 'Date_Missing, '
WHEN a.Unclear_Images = 'Yes' THEN #strFYI = #strFYI + 'Unclear_Images, '
WHEN a.Damage = 'Yes' THEN #strFYI = #strFYI + 'Damage, '
ELSE #strFYI
END AS FYI_Reasons
FROM
questionaretable a
But obviously that doesn't work. I'll also need to trim the last comma and space off the list once it's generated, but that shouldn't be a problem... I'm just not sure how to iterate through my records and build this concatenation in tsql :) I'm not even sure (because the syntax is wrong) if the variable would be reset to '' before each record was evaluated!
Can anyone help me out here?
This will be very ugly for 70 columns.
SELECT record_num, LEFT(strFYI, LEN(strFYI) - 2)
FROM (
SELECT
a.record_num,
(CASE WHEN a.Date_Missing = 'Yes' THEN 'Date_Missing, ' ELSE '' END) +
(CASE WHEN a.Unclear_Images = 'Yes' THEN 'Unclear_Images, ' ELSE '' END) +
(CASE WHEN a.Damage = 'Yes' THEN 'Damage, ' ELSE '' END) as strFYI
FROM
questionaretable a
) T
Maybe is cleaner using IIF
IIF ( boolean_expression, true_value, false_value )
SELECT record_num, LEFT(strFYI, LEN(strFYI) - 2)
FROM (
SELECT
a.record_num,
IIF(a.Date_Missing = 'Yes', 'Date_Missing, ' , '' ) +
IIF(a.Unclear_Images = 'Yes', 'Unclear_Images, ', '') +
IIF(a.Damage = 'Yes', 'Damage, ', '') as strFYI
FROM
questionaretable a
) T
As CElliot mention not IIF in 2008 so another solution may be
isnull((select 'Date_Missing, ' where a.Date_Missing = 'Yes'),'')

Printing out list of attribute descriptions based on boolean columns in SQL

I've got a table with a few boolean columns like: IsProductionWorker, IsMaterialHandler, IsShopSupervisor, etc. A record in this table may have several of these column values as true.
What I would like to do is have a query that returns 1 field with a list of all the attributes that are true, say AttributeList which, if those 3 columns were true would return: "Production Worker, Material Handler, Shop Supervisor".
I can think of a few brute force methods and maybe a more elegant method through the use of a temp-table (I've done similar things before), but I'm curious as to what the best way of doing this would be and if there are any easier implementations.
Thanks.
No elegance is possible, really. Simplicity, yes.
Per row you want to change a flag into a string, for each flag. Not many options for cleverness...
SELECT
SUBSTRING (
CASE WHEN IsProductionWorker = 1 THEN ', Production Worker' ELSE '' END +
CASE WHEN IsMaterialHandler= 1 THEN ', Material Handler' ELSE '' END +
CASE WHEN IsShopSupervisor= 1 THEN ', Shop Supervisor' ELSE '' END +
... ,
3, 8000)
FROM
MyTable
WHERE
...
You can try this.
select CASE WHEN isProductionWorker = 1 THEN 'Production Worker' ELSE '' END
+ CASE WHEN cast(isProductionWorker as int) + isMaterialHandler = 2 THEN ', ' else '' END
+ CASE WHEN isMaterialHandler = 1 THEN 'Material Handler' ELSE '' END
+ CASE WHEN cast(isProductionWorker as int) + isMaterialHandler + isShopSupervisor > 1 THEN ', ' else '' END
+ CASE WHEn isShopSupervisor = 1 THEN 'Shop Supervisor' ELSE '' END AS AttributeList
from MyTable