CONCAT'ing NULL fields - sql

I have a table with three fields, FirstName, LastName and Email.
Here's some dummy data:
FirstName | LastName | Email
Adam West adam#west.com
Joe Schmoe NULL
Now, if I do:
SELECT CONCAT(FirstName, LastName, Email) as Vitals FROM MEMBERS
Vitals for Joe is null, as there is a single null field. How do you overcome this behaviour? Also, is this the default behaviour in MS SQL Server?

Try
ISNULL(FirstName, '<BlankValue>') -- In SQL Server
IFNULL(Firstname, '<BlankValue>') -- In MySQL
So,
CONCAT(ISNULL(FirstName,''),ISNULL(LastName,''),ISNULL(Email,'')) -- In SQL Server
CONCAT(IFNULL(FirstName,''),IFNULL(LastName,''),IFNULL(Email,'')) -- In MySQL
would return the same thing without the null issue (and a blank string where nulls should be).

Look at CONCAT_WS
For example:
CONCAT_WS('',NULL,"TEST STRING","TEST STRING 2")
Yields
TEST STRINGTEST STRING 2
This is easier than constructing IFNULL around everything. You can use an empty string as the separator.

In mysql isnull wont work some time. try IFNULL(),
CONCAT(IFNULL(FirstName,''),IFNULL(LastName,''),IFNULL(Email,''))

SELECT ISNULL(FirstName,'')+ISNULL(LastName,'')+ISNULL(Email,'') as Vitals FROM MEMBERS
is recommended, but if you are really hooked on CONCAT, wrap it in {fn } and you can use the ODBC function like:
SELECT {fn CONCAT(ISNULL(FirstName,''), ISNULL(LastName,''), ISNULL(Email,''))} as Vitals FROM MEMBERS
If you need first<space>last but just last when first is null you can do this:
ISNULL(FirstName+' ','') + ISNULL(LastName,'')
I added the space on firstname which might be null -- that would mean the space would only survive if FirstName had a value.
To put them all together with a space between each:
RTRIM(ISNULL(Firstname+' ','') + ISNULL(LastName+' ','') + ISNULL(Email,''))

You can always use the CONCAT_NULL_YIELDS_NULL setting..
just run SET CONCAT_NULL_YIELDS_NULL OFF and then all null concatenations will result in text and not null..

If you get (like I do in MySQL):
#1582 - Incorrect parameter count in the call to native function 'ISNULL'
You can replace ISNULL function by COALESCE:
CONCAT(COALESCE(FirstName,''),COALESCE(LastName,''),COALESCE(Email,''))

Stefan's answer is correct.
To probe a little bit deeper you need to know that NULL is not the same as Nothing. Null represents the absence of a value, or in other words, not defined. Nothing represents an empty string which IS in fact a value.
Undefined + anything = undefined
Good database tidbit to hold onto!

Starting from MS SQL Server 2012 it was introduced CONCAT function
and according to MSDN
Null values are implicitly converted to an empty string. If all the
arguments are null, an empty string of type varchar(1) is returned.
so it's enough to use CONCAT without IsNull
CONCAT(FirstName, LastName, Email)

SQL Server does not have a CONCAT function.
(Update: Starting from MS SQL Server 2012 it was introduced CONCAT function)
In the default SQL Server behavior, NULLs propagate through an expression.
In SQL Server, one would write:
SELECT FirstName + LastName + Email as Vitals FROM MEMBERS
If you need to handle NULLs:
SELECT ISNULL(FirstName, '') + ISNULL(LastName, '') + ISNULL(Email, '') as Vitals FROM MEMBERS

In the case of MS Access
Option 1) SELECT (FirstName + " " + LastName + " " + Email) as Vitals FROM MEMBERS
You will get blank result in the case of any field with null.
Option 2) SELECT (FirstName & " " & LastName & " " & Email) as Vitals FROM MEMBERS
You will get Space in place of field with null.

After observing the answers for this question, you may combine all of them into one simple solution
CONCAT_WS(',',
IF(NULLIF(FirstName, '') IS NULL, NULL, FirstName),
IF(NULLIF(LastName, '') IS NULL, NULL, usr_lastname),
IF(NULLIF(Email, '') IS NULL, NULL, Email))
So, in short we use CONCAT_WS to concatenate our fields and separate them with ,; and notice that NULL fields nor EMPTY wont concatenated
NULLIF will check if the field is NULL or EMPTY, a field that contains only spaces or is empty as well, ex: '', ' ') and the output will be either NULL or NOT NULL
IF Will out put the field if it's not NULL or EMPTY

Related

Concatenating Full Names in Microsoft SQL Server

Suppose I have a table with the following information
Title FirstName MiddleName LastName Suffix
======|============|=============|============|======
Mr. John Fitzgerald Kennedy NULL
NULL John NULL Doe III
I want to create a query to output the full name of the above information. For example, I want the output to look like
Mr. John Fitzgerald Kennedy
John Doe, III
I was thinking of using the concat() function, but I am unsure how to go about this to ensure I don't have extra spaces or hanging commas in the names.
This is a little tricky. SQL Server 2017+ supports concat_ws(). However, you still need a comma for the suffix. Forturnately, concat() ignores NULLs:
select concat(concat_ws(' ', title, firstname, middlename, lastname),
', ' + suffix
)
Earlier versions require a bit more work to avoid multiple spaces when there are NULL values:
select ltrim(concat(' ' + title,
' ' + firstname,
' ' + middlename,
' ' + lastname,
', ' + suffix
)
)
This uses the fact that + returns NULL when an argument is NULL. But, concat() ignores it.
Note: Neither probably does what you want if all the names are NULL but the suffix is present. However, I doubt that is an issue in your data.
Here is a db<>fiddle.

Concatenate with NULL values in SQL

Column1 Column2
------- -------
apple juice
water melon
banana
red berry
I have a table which has two columns. Column1 has a group of words and Column2 also has a group of words. I want to concatenate them with + operator without a space.
For instance: applejuice
The thing is, if there is a null value in the second column, i only want to have the first element as a result.
For instance: banana
Result
------
applejuice
watermelon
banana
redberry
However, when i use column1 + column2, it gives a NULL value if Comunm2 is NULL. I want to have "banana" as the result.
Use the COALESCE function to replace NULL values with an empty string.
SELECT Column1 + COALESCE(Column2, '') AS Result
FROM YourTable
A few posts I have made tagged MSSQL have been renamed to 'SQL' by a moderator. So I am assuming you are using MSSQL
COALESCE will return the FIRST non-null value.
SELECT COALESCE('a', NULL, 'c')
will only return 'a'
If you want Firstname + Lastname, where sometimes one or the other is NULL, use CONCAT. Concat adds the strings together and replaces NULLS with 0 length non-null value.
SELECT CONCAT('a', NULL, 'c')
will return 'ac'
If you want Fn space + middle name space + LN, combine concatinate with CONCAT:
SELECT CONCAT('a' + ' ', NULL + ' ', 'c')
Will return 'a c'.
The space after middlename (null) is eliminated with the + and NULL.
NULL + ' ' is null.
So in cases where Middlename or Firstname is null, you won't get extra unwanted spaces.
Standard SQL requires that string concatenation involving a NULL generates a NULL output, but that is written using the || operation:
SELECT a || b
FROM SomeTable;
The output will be null if either a or b or both contains a NULL.
Using + to concatenate strings indicates that you are using a DBMS-specific extension. The behaviour might be the same as the standard requires - indeed, that seems to be the gist of your question.
Some DBMS - notably Oracle - tend to treat null strings as equivalent to empty strings; then you can concatenate away merrily. However, that behaviour is not strictly standard-compliant if the || operator is used.
Consider using COALESCE or NVL or IFNULL or some similar function to map the NULL to an empty string before concatenating.
If you are using MySq, use ifnull(Column2, '')
I'm not certain what you're using as your database, but I would look for a "coalesce" function for your particular SQL dialect and use that.
The + sign for concatenation in TSQL will by default combine string + null to null as an unknown value.
You can do one of two things, you can change this variable for the session which controlls what Sql should do with Nulls
http://msdn.microsoft.com/en-us/library/ms176056.aspx
Or you can Coalesce each column to an empty string before concatenating.
COALESCE(Column1, '')
http://msdn.microsoft.com/en-us/library/ms190349.aspx
You can do a union:
(SELECT Column1 + Column2 FROM Table1 WHERE Column2 is not NULL)
UNION
(SELECT Column1 FROM Table1 WHERE Column2 is NULL);
You can use a case condition:
case when column_2 is not null
then concatenate
else column_1
end

SQL Like query last match

I've a database that has a name field. (i.e Firstname M. Lastname or just Firstname Lastname).
Trying to filter by lastname.
How can I do a query to find the last space?
Something like
select * from person where name like "% a%" (but the space is the last space)
Thanks,
Tee
If using some version of Microsoft SQL Server, you could reverse() the string, and then use charindex() to find the first space.
If this is mySQL, you can consider using the SUBSTRING_INDEX() function (with count = -1).
SELECT CASE WHEN [Name] LIKE '% [^ ]%'
THEN SUBSTRING([Name],
LEN([Name]) - CHARINDEX(' ', REVERSE([Name])) + 1,
8000)
ELSE [Name]
END AS [LastName]
FROM [Customers]

What is the Null Character literal in TSQL?

I am wondering what the literal for a Null character (e.g. '\0') is in TSQL.
Note: not a NULL field value, but the null character (see link).
I have a column with a mix of typical and a null character. I'm trying to replace the null character with a different value. I would have thought that the following would work but it is unsuccessfull:
select REPLACE(field_with_nullchar, char(0), ',') from FOO where BAR = 20
There are two different behaviors in the Cade Roux's answer: replacement is successful (when SQL collation is used) and unsuccessful (Windows collation is used). The reason is in type of collation used.
This behaviour was submitted to Microsoft nearly 4 years ago:
Q: When trying a replace a NUL character
with replace(), this works is the
value has an SQL collation, but not a
Windows collation.
A: This is due to the fact that 0x0000
is an undefined character in Windows
collations. All undefined characters
are ignored during comparison, sort,
and pattern matching. So searing for
'a' + char(0) is really searching for
‘a’, and searching for char(0) is
equivalent to empty string.
The way to handle undefined character
is a bit confusing, but this is the
way that Windows defined to sort them,
and SQL Server conforms with the
general Windows API.
In SQL collation, there is no notion
of undefined character. Each code
point is assigned a weight, that's why
we don't see a problem there.
but unfortunately, it is still undocumented.
So, it seems the only one solution is to change collation to SQL collation (e.g. SQL_Latin1_General_CP1_CI_AS may be used as well).
* I removed my previous answer as unnecessary
Looks like the C-style terminator is a terminator in SQL as well:
SELECT REPLACE(bad, CHAR(0), ' ')
FROM (
SELECT 'a' + CHAR(0) + 'b' AS bad
) AS X
Looks like it's also dependent on COLLATION:
SELECT REPLACE(CAST(bad COLLATE SQL_Latin1_General_CP1_CI_AS AS varchar(10)), CHAR(0), ' ')
FROM (
SELECT 'a' + CHAR(0) + 'b' AS bad
) AS X
works as expected, compared to:
SELECT REPLACE(CAST(bad COLLATE Latin1_General_CI_AS AS varchar(10)), CHAR(0), ' ')
FROM (
SELECT 'a' + CHAR(0) + 'b' AS bad
) AS X
A VARBINARY cast should work with any collation
SELECT
REPLACE(CAST(CAST(fld AS VARCHAR(5)) AS VARBINARY(5)), 0x0, ',')
FROM
(SELECT 'QQ' + CHAR(0) + 'WW' COLLATE Latin1_General_CI_AS AS fld) AS T
SELECT
REPLACE(CAST(CAST(fld AS VARCHAR(5)) AS VARBINARY(5)), 0x0, ',')
FROM
(SELECT 'QQ' + CHAR(0) + 'WW' COLLATE SQL_Latin1_General_CP1_CI_AS AS fld) AS T
>>QQ,WW
>>QQ,WW
I just ran the test below on my server (2008) and it was successful. It may have to do with an ANSI setting. I'll try flipping some settings here and see if I can reproduce your issue.
DECLARE #test_null_char VARCHAR(20)
SET #test_null_char = 'aaa' + CHAR(0) + 'bbb'
SELECT #test_null_char -- Returns "aaa bbb"
SET #test_null_char = REPLACE(#test_null_char, CHAR(0), 'ccc')
SELECT #test_null_char -- Returns "aaacccbbb"
Are you certain they are null characters? How did you get them in there?
It looks like SQL Server treats them as string terminators. This query:
select 'aaa' + char(0) + 'bbb'
Returns aaa for me (on SQL Server 2008).
Edit: Above is wrong - it's just the results grid that treats them that way. They show up in text mode.
I was having the same issue and using nullif solved it for me.
Select nullif(field_with_nullchar,'') from FOO where BAR = 20

SQL strip text and convert to integer

In my database (SQL 2005) I have a field which holds a comment but in the comment I have an id and I would like to strip out just the id, and IF possible convert it to an int:
activation successful of id 1010101
The line above is the exact structure of the data in the db field.
And no I don't want to do this in the code of the application, I actually don't want to touch it, just in case you were wondering ;-)
This should do the trick:
SELECT SUBSTRING(column, PATINDEX('%[0-9]%', column), 999)
FROM table
Based on your sample data, this that there is only one occurence of an integer in the string and that it is at the end.
I don't have a means to test it at the moment, but:
select convert(int, substring(fieldName, len('activation successful of id '), len(fieldName) - len('activation successful of id '))) from tableName
Would you be open to writing a bit of code? One option, create a CLR User Defined function, then use Regex. You can find more details here. This will handle complex strings.
If your above line is always formatted as 'activation successful of id #######', with your number at the end of the field, then:
declare #myColumn varchar(100)
set #myColumn = 'activation successful of id 1010102'
SELECT
#myColumn as [OriginalColumn]
, CONVERT(int, REVERSE(LEFT(REVERSE(#myColumn), CHARINDEX(' ', REVERSE(#myColumn))))) as [DesiredColumn]
Will give you:
OriginalColumn DesiredColumn
---------------------------------------- -------------
activation successful of id 1010102 1010102
(1 row(s) affected)
select cast(right(column_name,charindex(' ',reverse(column_name))) as int)
CAST(REVERSE(LEFT(REVERSE(#Test),CHARINDEX(' ',REVERSE(#Test))-1)) AS INTEGER)
-- Test table, you will probably use some query
DECLARE #testTable TABLE(comment VARCHAR(255))
INSERT INTO #testTable(comment)
VALUES ('activation successful of id 1010101')
-- Use Charindex to find "id " then isolate the numeric part
-- Finally check to make sure the number is numeric before converting
SELECT CASE WHEN ISNUMERIC(JUSTNUMBER)=1 THEN CAST(JUSTNUMBER AS INTEGER) ELSE -1 END
FROM (
select right(comment, len(comment) - charindex('id ', comment)-2) as justnumber
from #testtable) TT
I would also add that this approach is more set based and hence more efficient for a bunch of data values. But it is super easy to do it just for one value as a variable. Instead of using the column comment you can use a variable like #chvComment.
If the comment string is EXACTLY like that you can use replace.
select replace(comment_col, 'activation successful of id ', '') as id from ....
It almost certainly won't be though - what about unsuccessful Activations?
You might end up with nested replace statements
select replace(replace(comment_col, 'activation not successful of id ', ''), 'activation successful of id ', '') as id from ....
[sorry can't tell from this edit screen if that's entirely valid sql]
That starts to get messy; you might consider creating a function and putting the replace statements in that.
If this is a one off job, it won't really matter. You could also use a regex, but that's quite slow (and in any case mean you now have 2 problems).