Concatenate columns in t-sql but exclude columns that are null - sql-server

SELECT 'Column 1: ' + t.Column1 +
'Column 2: ' + t.Column2 +
'Column 3: ' + t.Column3
from Table1 t
So I need a custom string before every column like shown. However, if Column2 is null, for example, I want to exclude the entire part 'Column 2: ' + t.Column2.
Where clause to only show not null columns is not what I'm looking for, since it's valid that all 3 columns are null for some rows.

In SQL Server, concatenating null to a string will result with null. Taking advantage of that fact, you can do something like this:
SELECT ISNULL('Column 1: ' + t.Column1, '') +
ISNULL('Column 2: ' + t.Column2, '') +
ISNULL('Column 3: ' + t.Column3, '')
FROM Table
In SQL Server 2012 or higher, you can use the Concat built in function, but you still need to concatenate the columns to their hard coded description the old fashion way to take advantage of the effect described before.
SELECT CONCAT('Column 1: ' + t.Column1,
'Column 2: ' + t.Column2,
'Column 3: ' + t.Column3)
FROM Table

Assuming CONCAT_NULL_YIELDS_NULL is turned on (it is by default and should be), you can do something like:
SELECT COALESCE('Column 1: ' + t.Column1,'') +
COALESCE('Column 2: ' + t.Column2,'') +
COALESCE('Column 3: ' + t.Column3,'')
from Table1 t
If any column is NULL then 'Column name ' + Column will be NULL. COALESCE then replaces NULLs with empty strings so that the outer +s are joining non-NULL strings.

Related

Error converting data type varchar to numeric. in Below sql Querys

SELECT ltrim(flexid + ' - ' + descr + ' ($' + max_deduct + ' deductible)') descr,
flexid
FROM [MHCSI].[FLEX_PLAN]
WHERE groupno = '0000080002' ORDER BY flexid;
The issue is that SQL Server assumed you want to perform a mathematical function to the max_deduct column. Because what you really want to do is just concatonate it to the rest of the string value that you are building, the easiest solution would be to make sure SQL Server understands you want to use the value of the column as a test value. You can do this by explicitly casting the value to a text-string.
Try rewriting your statement to this:
SELECT
ltrim(flexid + ' - ' + descr + ' ($' + CAST(max_deduct AS nvarchar(50)) + ' deductible)') descr
, flexid
FROM
[MHCSI].[FLEX_PLAN]
WHERE
groupno = '0000080002' ORDER BY flexid;

Need help adding WHERE clause in pre-written SQL statement

Preface: my SQL is rudimentary. I received a SQL query from a vendor, it selects and exports every single employee comment and other data from a few different DBs as CSV meant for import, it was written by them but they're not helping with this request. The query is pulling so much data it makes a large time consuming file for import. So I want to add to / modify the query to have a "WHERE date > whateverdate" to narrow my results to recent data. For example, I want to pull only comments entered in the past 2 days.
The column I'm looking to add the clause for is the column "A.CMS502", defined as datetime. I believe this is the only relevant column in this query. An example date in this column is "2003-10-06 17:05:21.000". I am using SQL Server 2008 if it helps. Is it possible here? Thank you.
SELECT
'ID,Acct/LnNbr,NoteCreatedDate,CollectorId,ApplytoAll,Note'
UNION ALL
SELECT
ID + ',' + ID + ',' + NoteCreatedDate + ',' + CollectorId + ',' + 'No' + ',' + Note
FROM
(SELECT
CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S'
THEN SUBSTRING(A.CMS301,1,LEN(A.CMS301) - 1)
ELSE A.CMS301
END + '-' +
CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S'
THEN 'S' ELSE 'L'
END AS [ID],
REPLACE(CONVERT(VARCHAR, A.CMS501, 10), '-', '') AS [NoteCreatedDate],
CASE WHEN U.CMS1201 IS NOT NULL
THEN U.CMS1205 + ' ' + U.CMS1204
ELSE (SELECT CMS1205 + ' ' + CMS1204 FROM sysUSER WHERE CMS1201 = 'PSUSER')
END AS CollectorId,
CAST(A.CMS512 AS NVARCHAR(MAX)) AS [Note]
FROM
ACTIVITY AS A
LEFT JOIN
sysUSER AS U ON A.CMS503 = U.CMS1201
WHERE
A.CMS504 NOT IN (411,500,511,711,804,900,901,903,907,2000,999777)
AND A.CMS504 NOT BETWEEN 1102 AND 1199) AS S
Try this, this will output last 2 days.
SELECT 'ID,Acct/LnNbr,NoteCreatedDate,CollectorId,ApplytoAll,Note'
UNION ALL
SELECT ID + ',' + ID + ',' + NoteCreatedDate + ',' + CollectorId + ',' + 'No' + ',' + Note
FROM
(
SELECT CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S' THEN SUBSTRING(A.CMS301,1,LEN(A.CMS301) - 1) ELSE A.CMS301 END
+ '-' + CASE WHEN SUBSTRING(A.CMS301,LEN(A.CMS301),1) = 'S' THEN 'S' ELSE 'L'
END AS [ID]
,REPLACE(CONVERT(varchar,A.CMS501,10),'-','') AS [NoteCreatedDate]
,CASE WHEN U.CMS1201 IS NOT NULL THEN U.CMS1205 + ' ' + U.CMS1204 ELSE
(SELECT CMS1205 + ' ' + CMS1204 FROM sysUSER WHERE CMS1201 = 'PSUSER')
END AS CollectorId
,CAST(A.CMS512 AS nvarchar(max)) AS [Note]
FROM ACTIVITY AS A
LEFT JOIN sysUSER AS U
ON A.CMS503 = U.CMS1201
WHERE A.CMS504 NOT IN (411,500,511,711,804,900,901,903,907,2000,999777)
AND A.CMS504 NOT BETWEEN 1102 AND 1199
AND A.CMS502 >= DATEADD(D, -2, GETDATE())
) AS S

Order by Empty String Last on Concatenated Column

I am trying to order a table alphabetically, ascending, with nulls last but am having problems.
The code below produces the following error:
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
select distinct
'item' = othertab..item,
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
order by case when stockedFor is null then 1 else 0 end, stockedFor
How can I return stockedFor alphabetically and nulls last?
Just wrap it in another select statement:
select stockedFor
from (
select distinct
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
) x
order by case when stockedFor is null then 1 else 0 end, stockedFor
Since you are removing duplicates, a workaround is to use GROUP BY to remove duplicates instead of DISTINCT. The question has changed but the method still applies if putting all columns in the SELECT in the GROUP BY.
For example:
select
'item' = othertab..item,
'stockedFor' = tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
from tab
GROUP BY othertab..item,
tab..stocked_for
+ ', ' + tab..stockedFor2
+ ', '+ tab..stockedFor3
order by case when stockedFor is null then 1 else 0 end, stockedFor

Generate column name dynamically in sql server

Please look at the below query..
select name as [Employee Name] from table name.
I want to generate [Employee Name] dynamically based on other column value.
Here is the sample table
s_dt dt01 dt02 dt03
2015-10-26
I want dt01 value to display as column name 26 and dt02 column value will be 26+1=27
I'm not sure if I understood you correctly. If I'am going into the wrong direction, please add comments to your question to make it more precise.
If you really want to create columns per sql you could try a variation of this script:
DECLARE #name NVARCHAR(MAX) = 'somename'
DECLARE #sql NVARCHAR(MAX) = 'ALTER TABLE aps.tbl_Fabrikkalender ADD '+#name+' nvarchar(10) NULL'
EXEC sys.sp_executesql #sql;
To retrieve the column name from another query insert the following between the above declares and fill the placeholders as needed:
SELECT #name = <some colum> FROM <some table> WHERE <some condition>
You would need to dynamically build the SQL as a string then execute it. Something like this...
DECLARE #s_dt INT
DECLARE #query NVARCHAR(MAX)
SET #s_dt = (SELECT DATEPART(dd, s_dt) FROM TableName WHERE 1 = 1)
SET #query = 'SELECT s_dt'
+ ', NULL as dt' + RIGHT('0' + CAST(#s_dt as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 1) as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 2) as VARCHAR), 2)
+ ', NULL as dt' + RIGHT('0' + CAST((#s_dt + 3) as VARCHAR), 2)
+ ' FROM TableName WHERE 1 = 1)
EXECUTE(#query)
You will need to replace WHERE 1 = 1 in two places above to select your data, also change TableName to the name of your table and it currently puts NULL as the dynamic column data, you probably want something else there.
To explain what it is doing:
SET #s_dt is selecting the date value from your table and returning only the day part as an INT.
SET #query is dynamically building your SELECT statement based on the day part (#s_dt).
Each line is taking #s_dt, adding 0, 1, 2, 3 etc, casting as VARCHAR, adding '0' to the left (so that it is at least 2 chars in length) then taking the right two chars (the '0' and RIGHT operation just ensure anything under 10 have a leading '0').
It is possible to do this using dynamic SQL, however I would also consider looking at the pivot operators to see if they can achieve what you are after a lot more efficiently.
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

SQL Server String Concatenation with Null

I am creating a computed column across fields of which some are potentially null.
The problem is that if any of those fields is null, the entire computed column will be null. I understand from the Microsoft documentation that this is expected and can be turned off via the setting SET CONCAT_NULL_YIELDS_NULL. However, there I don't want to change this default behavior because I don't know its implications on other parts of SQL Server.
Is there a way for me to just check if a column is null and only append its contents within the computed column formula if its not null?
You can use ISNULL(....)
SET #Concatenated = ISNULL(#Column1, '') + ISNULL(#Column2, '')
If the value of the column/expression is indeed NULL, then the second value specified (here: empty string) will be used instead.
From SQL Server 2012 this is all much easier with the CONCAT function.
It treats NULL as empty string
DECLARE #Column1 VARCHAR(50) = 'Foo',
#Column2 VARCHAR(50) = NULL,
#Column3 VARCHAR(50) = 'Bar';
SELECT CONCAT(#Column1,#Column2,#Column3); /*Returns FooBar*/
Use COALESCE. Instead of your_column use COALESCE(your_column, ''). This will return the empty string instead of NULL.
You can also use CASE - my code below checks for both null values and empty strings, and adds a seperator only if there is a value to follow:
SELECT OrganisationName,
'Address' =
CASE WHEN Addr1 IS NULL OR Addr1 = '' THEN '' ELSE Addr1 END +
CASE WHEN Addr2 IS NULL OR Addr2 = '' THEN '' ELSE ', ' + Addr2 END +
CASE WHEN Addr3 IS NULL OR Addr3 = '' THEN '' ELSE ', ' + Addr3 END +
CASE WHEN County IS NULL OR County = '' THEN '' ELSE ', ' + County END
FROM Organisations
Use
SET CONCAT_NULL_YIELDS_NULL OFF
and concatenation of null values to a string will not result in null.
Please note that this is a deprecated option, avoid using.
See the documentation for more details.
I just wanted to contribute this should someone be looking for help with adding separators between the strings, depending on whether a field is NULL or not.
So in the example of creating a one line address from separate fields
Address1, Address2, Address3, City, PostCode
in my case, I have the following Calculated Column which seems to be working as I want it:
case
when [Address1] IS NOT NULL
then ((( [Address1] +
isnull(', '+[Address2],'')) +
isnull(', '+[Address3],'')) +
isnull(', '+[City] ,'')) +
isnull(', '+[PostCode],'')
end
Hope that helps someone!
ISNULL(ColumnName, '')
I had a lot of trouble with this too. Couldn't get it working using the case examples above, but this does the job for me:
Replace(rtrim(ltrim(ISNULL(Flat_no, '') +
' ' + ISNULL(House_no, '') +
' ' + ISNULL(Street, '') +
' ' + ISNULL(Town, '') +
' ' + ISNULL(City, ''))),' ',' ')
Replace corrects the double spaces caused by concatenating single spaces with nothing between them. r/ltrim gets rid of any spaces at the ends.
In Sql Server:
insert into Table_Name(PersonName,PersonEmail) values(NULL,'xyz#xyz.com')
PersonName is varchar(50), NULL is not a string, because we are not passing with in single codes, so it treat as NULL.
Code Behind:
string name = (txtName.Text=="")? NULL : "'"+ txtName.Text +"'";
string email = txtEmail.Text;
insert into Table_Name(PersonName,PersonEmail) values(name,'"+email+"')
This example will help you to handle various types while creating insert statements
select
'insert into doc(Id, CDate, Str, Code, Price, Tag )' +
'values(' +
'''' + convert(nvarchar(50), Id) + ''',' -- uniqueidentifier
+ '''' + LEFT(CONVERT(VARCHAR, CDate, 120), 10) + ''',' -- date
+ '''' + Str+ ''',' -- string
+ '''' + convert(nvarchar(50), Code) + ''',' -- int
+ convert(nvarchar(50), Price) + ',' -- decimal
+ '''' + ISNULL(Tag, '''''') + '''' + ')' -- nullable string
from doc
where CDate> '2019-01-01 00:00:00.000'

Resources