SQL empty strings and text formatting - sql

I am trying to do some text formatting with sql (MS SQL server 2008). I have three variables which are either going to return empty strings or some sort of text, they will never be null. I would like the display the text in the following way:
#Var1='A' #Var2='B' #Var3='C' ==> A, B, C
#Var1='A' #Var2='' #Var3='C' ==> A, C
#Var1='' #Var2='B' #Var3='C' ==> B, C
#Var1='' #Var2='' #Var3='C' ==> C
.
.
.
#Var1='' #Var2='' #Var3='' ==>
etc
Here is a simplified version of what I have...
DECLARE #Var1 NVARCHAR(100)
DECLARE #Var2 NVARCHAR(100)
DECLARE #Var3 NVARCHAR(100)
SET #Var1 = 'A'
SET #Var2 = 'B'
SET #Var3 = 'C'
SELECT
ISNULL(NULLIF(#Var1,''), '')
+
CASE
WHEN NULLIF(#Var1,'') IS NOT NULL AND NULLIF(#Var2,'') IS NOT NULL THEN ', ' ELSE ''
END
+
ISNULL(NULLIF(#Var2,''),'')
+
CASE
WHEN NULLIF(#Var2,'') IS NOT NULL AND NULLIF(#Var3,'') IS NOT NULL THEN ', ' ELSE ''
END
+
ISNULL(NULLIF(#Var3,''),'')
I feel like I am missing some important details. Let me know if there is any clarification needed.

Try:
select case
when str is null then ''
else left(str, len(str)-1) -- Remove last comma
end
from (
select case when len(#Var1) > 0 then #Var1 + ', ' else '' end +
case when len(#Var2) > 0 then #Var2 + ', ' else '' end +
case when len(#Var3) > 0 then #Var3 + ', ' else '' end as str
) as SubQueryAlias
Or with a reverse trick to avoid the subquery:
select reverse(stuff(reverse(
case when len(#Var1) > 0 then #Var1 + ', ' else '' end +
case when len(#Var2) > 0 then #Var2 + ', ' else '' end +
case when len(#Var3) > 0 then #Var3 + ', ' else '' end
), 1, 2, ''));
The key point here is that SQL Server is not very good at text formatting :) You're infinitely better off in a client side language like C#.
Live example at SQL Fiddle.

Related

Filter data by keywords and note where they were found

so i have a query at the moment.
SELECT *
FROM TABLE1
It yields besides other stuff 4 colums which contain text "Textbox1" "Textbox2" "Textbox3" "Textbox4".
I now want to filter this query by keywords in those text boxes. Basically the user can enters 0 to 5 keywords and the rows from TABLE1 should only show if at least one keyword was found in one of the textboxes. Also a new column should be added that for every keyword that was found in a textbox should say which keyword and in which textboxes it was found.
The query itself will later run in SSRS which is where the user puts in the keywords. So the keywords are accasable as varchars. For the query you can use this:
DECLARE #Keyword1 AS VARCHAR(100) = '';
DECLARE #Keyword2 AS VARCHAR(100) = '';
DECLARE #Keyword3 AS VARCHAR(100) = '';
DECLARE #Keyword4 AS VARCHAR(100) = '';
DECLARE #Keyword5 AS VARCHAR(100) = '';
Thanks for any help.
Edit:
This is a very unelegant solution and it's not exactly what you wanted but hopefully close enough.
To improve it, especially if you are goning to extend this to more column/keywords I would consider unpivoting the data, testing each row and then aggregating the result of that back up again.
DECLARE #t TABLE (T1 varchar(100), T2 varchar(100), T3 varchar(100), T4 varchar(100))
INSERT INTO #t VALUES
(1, 11, 203, 30),
(8898, 54452, 1222, 12122)
DECLARE #k1 varchar(100) = '1'
DECLARE #k2 varchar(100) = '22'
SET #k1 = '%' + #k1 + '%'
SET #k2 = '%' + #k2 + '%'
SELECT
*
, CASE WHEN T1 like #k1 THEN '1:T1 ' ELSE '' END +
CASE WHEN T2 like #k1 THEN '1:T2 ' ELSE '' END +
CASE WHEN T3 like #k1 THEN '1:T3 ' ELSE '' END +
CASE WHEN T4 like #k1 THEN '1:T4 ' ELSE '' END +
CASE WHEN T1 like #k2 THEN '2:T1 ' ELSE '' END +
CASE WHEN T2 like #k2 THEN '2:T2 ' ELSE '' END +
CASE WHEN T3 like #k2 THEN '2:T3 ' ELSE '' END +
CASE WHEN T4 like #k2 THEN '2:T4 ' ELSE '' END
As Found
FROM #t
This give the following results.
With the help of Alan Schofield i found the solution that i need.
SELECT * from( Select*,
CASE WHEN Textbox1 like '%'+#Keyword1+'%' AND #Keyword1 <> '' THEN #Keyword1 +', ' ELSE '' END +
CASE WHEN Textbox1 like '%'+#Keyword2+'%' AND #Keyword2 <> '' THEN #Keyword2 +', ' ELSE '' END +
CASE WHEN Textbox1 like '%'+#Keyword3+'%' AND #Keyword3 <> '' THEN #Keyword3 +', ' ELSE '' END +
CASE WHEN Textbox1 like '%'+#Keyword4+'%' AND #Keyword4 <> '' THEN #Keyword4 +', ' ELSE '' END +
CASE WHEN Textbox1 like '%'+#Keyword5+'%' AND #Keyword5 <> '' THEN #Keyword5 +', ' ELSE '' END
As Textbox1found,
CASE WHEN Textbox2 like '%'+#Keyword1+'%' AND #Keyword1 <> '' THEN #Keyword1 +', ' ELSE '' END +
CASE WHEN Textbox2 like '%'+#Keyword2+'%' AND #Keyword2 <> '' THEN #Keyword2 +', ' ELSE '' END +
CASE WHEN Textbox2 like '%'+#Keyword3+'%' AND #Keyword3 <> '' THEN #Keyword3 +', ' ELSE '' END +
CASE WHEN Textbox2 like '%'+#Keyword4+'%' AND #Keyword4 <> '' THEN #Keyword4 +', ' ELSE '' END +
CASE WHEN Textbox2 like '%'+#Keyword5+'%' AND #Keyword5 <> '' THEN #Keyword5 +', ' ELSE '' END
As Textbox2found,
CASE WHEN Textbox3 like '%'+#Keyword1+'%' AND #Keyword1 <> '' THEN #Keyword1 +', ' ELSE '' END +
CASE WHEN Textbox3 like '%'+#Keyword2+'%' AND #Keyword2 <> '' THEN #Keyword2 +', ' ELSE '' END +
CASE WHEN Textbox3 like '%'+#Keyword3+'%' AND #Keyword3 <> '' THEN #Keyword3 +', ' ELSE '' END +
CASE WHEN Textbox3 like '%'+#Keyword4+'%' AND #Keyword4 <> '' THEN #Keyword4 +', ' ELSE '' END +
CASE WHEN Textbox3 like '%'+#Keyword5+'%' AND #Keyword5 <> '' THEN #Keyword5 +', ' ELSE '' END
As Textbox3found,
CASE WHEN Textbox4 like '%'+#Keyword1+'%' AND #Keyword1 <> '' THEN #Keyword1 +', ' ELSE '' END +
CASE WHEN Textbox4 like '%'+#Keyword2+'%' AND #Keyword2 <> '' THEN #Keyword2 +', ' ELSE '' END +
CASE WHEN Textbox4 like '%'+#Keyword3+'%' AND #Keyword3 <> '' THEN #Keyword3 +', ' ELSE '' END +
CASE WHEN Textbox4 like '%'+#Keyword4+'%' AND #Keyword4 <> '' THEN #Keyword4 +', ' ELSE '' END +
CASE WHEN Textbox4 like '%'+#Keyword5+'%' AND #Keyword5 <> '' THEN #Keyword5 +', ' ELSE '' END
AS Textbox4found
FROM Table1)as Result
WHERE Result.Textbox1found <> '' OR Result.Textbox2found <> '' OR Result.Textbox3found <> '' OR Result.Textbox4found <> '' or (#Keyword1='' AND #Keyword2='' AND #Keyword3='' AND #Keyword4='' AND #Keyword5='')
I switched to a Textbox based query which will generat for every textbox a column with the keywords found in that textbox.

How to return desired manual value based on specific parameters in SQL Server 2008

I have a SQL query in SQL Server 2008 like this:
declare #Waited6_8 varchar(max) = 'true'
declare #Waited8_12 varchar(max) = 'false'
declare #Waited12_18 varchar(max) = 'true'
Select
choice = case when #Waited6_8 = 'true' then '6-8'
when #Waited8_12 = 'true' then '8-12'
when #Waited12_18 = 'true' then '12-18'
end
Here, I get 6-8 as the result.
What I would like to see is: 6-8, 12-18 as one string (not as different rows)
How can I get this? I appreciate if you help.
Thanks!
declare #Waited6_8 varchar(max) = 'true'
declare #Waited8_12 varchar(max) = 'false'
declare #Waited12_18 varchar(max) = 'true'
Select choice = isnull(case when #Waited6_8 = 'true' then '6-8' end + ', ','') +
isnull(case when #Waited8_12 = 'true' then '8-12' end + ', ','') +
isnull(case when #Waited12_18 = 'true' then '12-18' end,'')
I think you might be better served with a few IF blocks.
DECLARE #Waited6_8 varchar(max) = 'true',
#Waited8_12 varchar(max) = 'false',
#Waited12_18 varchar(max) = 'true',
#Choice VARCHAR(MAX)
IF (#Waited6_8 = 'true')
BEGIN
SET #Choice += '6-8 ';
END
IF (#Waited8_12 = 'true')
BEGIN
SET #Choice += '8-12 ';
END
IF (Waited12_18 = 'true')
BEGIN
SET #Choice += '12-18';
END
PRINT RTRIM(#Choice);
The query you write, it is like if-else if statement that's why you get one value (6-8 here). You can get your desired result by using this query.
Select choice = (case when #Waited6_8 = 'true' then '6-8' else '' end) +
(case when #Waited6_8 = 'true' and #Waited8_12 = 'true' then ', ' else '' end) +
(case when #Waited8_12 = 'true' then '8-12' else '' end) +
(case when (#Waited6_8 = 'true' or #Waited8_12 = 'true') and #Waited12_18 = 'true' then ', ' else '' end) +
(case when #Waited12_18 = 'true' then '12-18' else '' end)
Here you have taken Case you can do it by performing just concatenation like,
declare #Waited6_8 varchar(max) = 'true'
declare #Waited8_12 varchar(max) = 'false'
declare #Waited12_18 varchar(max) = 'true'
Select choice = isnull(case when #Waited6_8 = 'true' then '6-8' end + ', ','') +
isnull(case when #Waited8_12 = 'true' then '8-12' end + ', ','') + //This case will get omitted as it contains null value
isnull(case when #Waited12_18 = 'true' then '12-18' end,'')
Check output,
Please refer working fiddle,http://sqlfiddle.com/#!6/9eecb7/8083, I have created this example regarding your question.this might solve all your questions.
Here It concats all 3 case,but omitting NULL value case so you will not get value of middle case.
Please note, make sure you put ISNULL before each case else it will also show you null value of middle case.

Dynamic SQL for CASE Statements to remove hardcode

I've a Dynamic SQL that is required to be optimized. I need to make CASE Expression Dynamic. I've a list of ATTRIBUTE_LIST & SCENARIO_LIST, that are provided below. I wrote a Function to get them Dynamically. How can I replace Three CASE Expression and make it Dynamic? I'm trying to avoid hard coding.
SET #ATTRIBUTE_LIST = 'symbol_type, currency, performing_status' -- INPUTS
SET #SCENARIO_LIST = 'historicalsimulation_1day_end_10dec2013, historicalsimulation_1day_end_11dec2013'
SELECT CASE
WHEN (GROUPING(Scenario_Name) = 1) THEN ''ALL''
WHEN (Scenario_Name = ''[BaseCase]'') THEN ''BaseCase''
ELSE ISNULL(Scenario_Name, '''')
END AS Scenario_Name,
CASE
WHEN (GROUPING(Symbol_Type) = 1) THEN ''ALL''
ELSE ISNULL(Symbol_Type, '''')
END AS Symbol_Type,
CASE
WHEN (GROUPING(Currency) = 1) THEN ''ALL''
ELSE ISNULL(Currency, '''')
END AS Currency,
CASE
WHEN (GROUPING(Performing_Status) = 1) THEN ''ALL''
ELSE ISNULL(Performing_Status, '''') \
END AS Performing_Status,
SUM(Value) AS ScenarioValue
FROM [20151005_171003_UserName_NT-22_Analysis_Tue] o
LEFT JOIN [20151005_171003_UserName_NT-22_Analysis_Tue_Position_Data] pld
ON o.Position_Unique_Identifier=pld.Position_Unique_Identifier
GROUP BY ' + #ATTRIBUTE_LIST + ' WITH CUBE) AS DATA
PIVOT ( Sum(scenariovalue)
FOR scenario_name IN (' + #SCENARIO_LIST + ')'
It appears you are using SQL Server. Here's a brute-force way of looping over your attributes and building a series of case expressions:
declare #cases nvarchar(max) = '';
declare #l varchar(max) = #ATTRIBUTE_LIST + ',';
declare #ofs int = 0;
declare #pos int = charindex(',', #l, #ofs + 1);
while #pos > 0
begin
if #cases <> '' set #cases = #cases + ',';
set #cases = #cases +
replace('
CASE WHEN (GROUPING(<COL>) = 1) THEN ''ALL''
ELSE ISNULL(<COL>, '''')
END AS <COL>',
'<COL>', substring(#l, #ofs + 1, #pos - #ofs - 1)
);
set #ofs = #pos;
set #pos = charindex(',', #l, #ofs + 1);
end
select #cases;

T SQL Conditional String Concatenation

Have a 5 columns of address data. I need to concatenate these fields into a single address with spaces in between the values if they exist. If the column has a null value I should skip it and not enter any space.
select
case
when street_number != '' THEN (cast(street_number as int))
end as street_number,
case
when street_ext != '' then
case
when street_ext = 50 then '1/2'
end
end as street_ext,
case
when street_direct ! = '' then street_direct
end as street_direct,
case
when site_street ! = '' then site_street
end as site_street,
case
when site_address ! = '' then site_address
end as site_address
from parcel
what I'd like to do is have a variable and assign it to the value of the first column street_number, then when I move on to the next column, street_ext, if it isn't null I'd like to check to see if the variable is null and if not, append a space and the value...and so on down the road.
I'm rusty as hell and could use a push in the right direction.
Thanks everyone.
Use the "+" to concatenate strings in TSQL:
SELECT CASE
WHEN LEN(p.street_number) > 0 THEN p.street_number + ' '
ELSE ''
END +
CASE
WHEN p.street_ext = 50 THEN '1/2'
WHEN LEN(p.street_ext) > 0 THEN ''
ELSE p.street_ext
END + ' ' +
CASE
WHEN LEN(p.street_direct) > 0 THEN p.street_direct + ' '
ELSE ''
END +
CASE
WHEN LEN(p.site_street) > 0 THEN p.site_street + ' '
ELSE ''
END +
CASE
WHEN LEN(p.site_address) > 0 THEN p.site_address + ' '
ELSE ''
END AS full_address
FROM PARCEL p
The LEN function returns zero if the string value is NULL, or a zero length string.
Nested isnulls could do what you need. Something like:
SELECT
ISNULL(streetnumber + ' ', '')
+ ISNULL(streetext + ' ', '')
etc
relying on the fact that NULL + ' ' = NULL.
Something along the lines of:
select coalesce(street_number+' ','')+
coalesce(case when street_ext=50 then '1/2' else null end+' ','')+
coalesce(street_direct+' ','')+
coalesce(site_street+' ','')+
coalesce(site_address,'')
from parcel
I have assumed your data types are all varchar or similar for simplicity. If you are OK with removing any double spaces, how about:
rtrim(ltrim(replace(isnull(street_number) + ' '
+ isnull(street_ext) + ' '
+ isnull(street_direct) + ' '
+ isnull(site_street) + ' '
+ isnull(site_address), ' ', ' ')))
First I would declare the seperator as a variable, because customers are notorious for changing these.
I would do this as follows:
DECLARE #AddressSeperator NVARCHAR(5) = ' '
...and then for the column declation, I'd use the following:
, CONCAT
(
(CASE WHEN LEN(p.street_number) > 0 THEN p.street_number + #AddressSeperator ELSE '' END)
, (CASE WHEN p.street_ext = 50 THEN '1/2' + #AddressSeperator WHEN LEN(p.street_ext) > 0 THEN p.street_ext + #AddressSeperator ELSE '' END)
, (CASE WHEN LEN(p.street_direct) > 0 THEN p.street_direct + #AddressSeperator ELSE '' END)
, (CASE WHEN LEN(p.site_street) > 0 THEN p.site_street + #AddressSeperator ELSE '' END)
, ISNULL(p.site_address, '')
) AS [full_address]

SQL Server Conditional Mailing Address Formatting

I have the following SQL to format a US address into each line for a mailing address but it is rather ugly. Is there a better way to solve this problem or does it have to be this ugly? Also, the problem with this code is that it always ends up with an extra new line at the end.
declare #NL varchar(2);
set #NL = char(13) + char(10);
select
case when rtrim(coalesce(AttentionLine,'') ) != '' then rtrim(AttentionLine ) + #NL else '' end
+ case when rtrim(coalesce(Recipient,'') ) != '' then rtrim(Recipient ) + #NL else '' end
+ case when rtrim(coalesce(AddlAddrLine,'') ) != '' then rtrim(AddlAddrLine ) + #NL else '' end
+ case when rtrim(coalesce(DeliveryAddr,'') ) != '' then rtrim(DeliveryAddr ) + #NL else '' end
+ case when rtrim(coalesce(LastLine,'') ) != '' then rtrim(LastLine ) + #NL else '' end
+ case when rtrim(coalesce(Country,'') ) != '' then rtrim(Country ) + #NL else '' end
as FormattedMailingAddress
from Address
where Id = 1
If your Sql Server Settings are such that NULL + varchar returns NULL (SET CONCAT_NULL_YIELDS_NULL (Transact-SQL)), this can help.
DECLARE #Address TABLE(
ID INT,
AttentionLine VARCHAR(50),
Recipient VARCHAR(50),
AddlAddrLine VARCHAR(50),
DeliveryAddr VARCHAR(50),
LastLine VARCHAR(50),
Country VARCHAR(50)
)
declare #NL varchar(2);
set #NL = char(13) + char(10);
INSERT INTO #Address SELECT 1, NULL, '1', NULL, '2', NULL, '3'
select
case when rtrim(coalesce(AttentionLine,'') ) != '' then rtrim(AttentionLine ) + #NL else '' end
+ case when rtrim(coalesce(Recipient,'') ) != '' then rtrim(Recipient ) + #NL else '' end
+ case when rtrim(coalesce(AddlAddrLine,'') ) != '' then rtrim(AddlAddrLine ) + #NL else '' end
+ case when rtrim(coalesce(DeliveryAddr,'') ) != '' then rtrim(DeliveryAddr ) + #NL else '' end
+ case when rtrim(coalesce(LastLine,'') ) != '' then rtrim(LastLine ) + #NL else '' end
+ case when rtrim(coalesce(Country,'') ) != '' then rtrim(Country ) + #NL else '' end
as FormattedMailingAddress ,
RTRIM(coalesce(AttentionLine + #NL,'')) +
RTRIM(coalesce(Recipient + #NL,'')) +
RTRIM(coalesce(AddlAddrLine + #NL,'')) +
RTRIM(coalesce(DeliveryAddr + #NL,'')) +
RTRIM(coalesce(LastLine + #NL,'')) +
RTRIM(coalesce(Country + #NL,''))
from #Address
where Id = 1
I realize this is an old question, but there is a new solution to this problem: the CONCAT_WS() function, which is new for SQL Server 2017 (it's also available for Azure SQL Database).
SELECT CONCAT_WS (
CHAR(13) + CHAR(10), --Separator
NULLIF(AttentionLine, ''),
NULLIF(Recipient, ''),
NULLIF(AddlAddrLine, ''),
NULLIF(DeliveryAddr, ''),
NULLIF(LastLine, ''),
NULLIF(Country, '')
)
AS FormattedMailingAddress
FROM Address
WHERE Id = 1
NULL values are ignored by the function, which is why NULLIF is used with each argument/parameter in this example. (When the argument/parameter evaluates to NULL, the separator won't be added either). Here's a short blog post with some more details: New For SQL Server 2017: T-SQL Function CONCAT_WS