isnull vs is null - sql

I have noticed a number of queries at work and on SO are using limitations in the form:
isnull(name,'') <> ''
Is there a particular reason why people do that and not the more terse
name is not null
Is it a legacy or a performance issue?

where isnull(name,'') <> ''
is equivalent to
where name is not null and name <> ''
which in turn is equivalent to
where name <> ''
(if name IS NULL that final expression would evaluate to unknown and the row not returned)
The use of the ISNULL pattern will result in a scan and is less efficient as can be seen in the below test.
SELECT ca.[name],
[number],
[type],
[low],
[high],
[status]
INTO TestTable
FROM [master].[dbo].[spt_values]
CROSS APPLY (SELECT [name]
UNION ALL
SELECT ''
UNION ALL
SELECT NULL) ca
CREATE NONCLUSTERED INDEX IX_TestTable ON dbo.TestTable(name)
GO
SELECT name FROM TestTable WHERE isnull(name,'') <> ''
SELECT name FROM TestTable WHERE name is not null and name <> ''
/*Can be simplified to just WHERE name <> '' */
Which should give you the execution plan you need.

is not null
Will only check if the field is not null. If the field contains an empty string, then the field is no longer null.
isnull(name, '') <> name
Checks for both a null and an empty string.

isnull(name,'') <> :name is shorthand for (name is null or name <> :name) (assuming that :name never contains the empty string, thus why shorthands like this can be bad).
Performance-wise, it depends. or statements in where clauses can give extremely bad performance. However, functions on columns impair index usage. As usual: profile.

isnull(name,'') <> name
Well I can see them using this because this way if the name doesn't match or is null it returns as a failed comparison. This really means: name is null or name <> name
Where as this one name is not null just checks to see if the name is null.

They don't mean the same thing.
name is not null
This checks for records where the name field is null
isnull(name,'') <> name
This one changes the value of null fields to the empty string so they can be used in a comparision. In SQL Server (but not in Oracle I think), if a value is null and it is used to compare equlaity or inequality it will not be considered becasue null means I don't know the value and thus is not an actual value. So if you want to make sure the null records are considered when doing the comparision, you need ISNULL or COALESCE(which is the ASCII STANDARD term to use as ISNULL doen't work in all databases).
What you should be looking at is the differnece between
isnull(a.name,'') <> b.name
a.name <> b.name
then you will understand why the ISNULL is needed to get correct results.

I apparently misread your question. So let me strike my first answer and try this one:
isnull(name,'') <> ''
is a misguided shortcut for
name is not null and name <> ''

Others have pointed out the functional difference. As to the performance issue, in Postgres I've found that -- oh, I should mention that Postgres has a function "coalesce" that is the equivalent of the "isnull" found in some other SQL dialects -- but in Postgres, saying
where coalesce(foobar,'')=''
is significantly faster than
where foobar is null or foobar=''
Also, it can be awesomely dramatically faster to say
where foobar>''
over
where foobar!=''
A greater than test can use the index and thus skip over all the blanks, while a not-equal test has to do a full file read. (Assuming you have an index on the field and no other index is used in preference.)

Also if you want to make use of the index on that column, use
name is not null and name <> ''

These two queries are not the same. For example, I do not have a middle name, this is a known fact, which can be stored as
MiddleName=''
However, if we don't know someone's middle name, we can store NULL.
So, ISNULL(MiddleName, '') means "persons without known middle names".

It is to handle both the empty string and NULL. While it is good to be able to do with with one statement, isnull is proprietary syntax. I would write this using portable Standard SQL as
NULLIF(name, '') IS NOT NULL

Related

How to treat NULLs like '' (empty data) in comparison WHERE statements

I know that if you try to compare a NULL value to something else. It being NULL makes the whole statement NULL.
table.ColumnA = NULL
table.ColumnB = 'something'
If I do something like
where table.ColumnA <> table.ColumnB
It will not work.
I know you can do something like,
(NOT (a <> b OR a IS NULL OR b IS NULL) OR (a IS NULL AND b IS NULL))
But my query is already pretty long and complicated. Trying to add this routine for every column would be a nightmare.
I was hoping there was an easier way to just temporarily treat NULL as ''
The logic for a <> b with NULL values is:
where (a <> b or a is null and b is not null or a is not null and b is null)
Unfortunately, SQL Server doesn't support the standard is distinct from clause, which would make this much simpler.
If there are values that you know will never be used, you can use coalesce():
where coalesce(a, '<null>') <> coalesce(b, '<null>')
Be careful blanket removing nulls, but if you need a quick solution to treat NULL as an empty string while preserving non-nulls you can use the coalesce function:
COALESCE(columnname, '')
Docs here:
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/coalesce-transact-sql?view=sql-server-ver15

what's the difference between is not null and <>' '

Look my example, what's the difference between two codes?
Select name from customers where name is not null
Select name from customers where name <> ''
They do completely different things.
Select name from customers where name is not null
This one selects any customer who has a value in the name field. Those values can include '' as well as things like 'Sam', 'John Jones', 'pretty blonde girl'.
Select name from customers where name <> ''
This will select all names that are not null or blank In Sql Server at least. Other databases may handle this differently. The reason why it also excludes Null is that Null cannot be part of a comparison since it by definition means we don't have a clue what the value of this field is.
If you wanted to return both real names and null values and only exclude the empty strings. In SQl Server you would do:
Select name from customers where coalesce(name, 'Unknown') <>''
There are a lot of correct answers here but I think you are missing what NULL is. It's nothing so it's not comparable to anything. Here's some test for you
DECLARE #param CHAR(1)=NULL --you can replace #param with your column name in your queries
SELECT 1 WHERE #param = NULL --you can't compare NULL to anything using = > < <> != or any other comparision operator
SELECT 1 WHERE #param = '' --an empty value isn't the same as a NULL value so if a NULL is present it won't be returned
SELECT 1 where #param IS NULL --this is how you have to check for null values
--If you want to check for both empty and nulls, you can force the empty string with COALESCE or ISNULL
SELECT 1 WHERE COALESCE(#param,'') = ''
SELECT 1 WHERE ISNULL(#param,'') = ''
The key concept you are missing is that in SQL Server, NULL does not mean no value, it means that the value is unknown. So consider your query with some silly sample data:
DECLARE #t TABLE
( id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
, name VARCHAR(10) NULL );
INSERT INTO #t
VALUES
('dog'),
('cat'),
(''),
(NULL);
SELECT *
FROM #t
WHERE name <> '';
What you are asking the engine is to return the records where name is not an empty string. On the evaluation of the fourth record, it is determining if NULL equals empty string or not. NULL could be empty string, we don't know ... given that the value is unknown, the engine can't include that record because you are asking for only records where we know the name is definitely not empty string.
Consider another query against the same data:
WITH cteTemp AS
(
SELECT *
, isEqualToEmptyString = CASE WHEN name = '' THEN 'true' ELSE 'false' END
FROM #t
)
SELECT *
FROM cteTemp
WHERE isEqualToEmptyString = 'false';
Now this is written to demonstrate a point and there are cleaner ways to do the same thing (such as the COALESCE in HLGEM's answer.) But understand what is happening here: the query is first determining for sure what names are empty string (which excludes the NULL since its value is unknown) and then excluding those that are. Thus, the NULL is returned.
Null and empty string are two different things. A given field in a table can either have no value (null) or a value of an empty string (''). The results return by each query will be mutually exclusive.
Is not null determines if the object/record being inspected is a true null value or not (no data).
<> '' means is not an empty string, so the record does contain data (that there is an empty string) and is not actually null.
So a query with is not null will return records with a value of string.empty, and a query with <> '' will return values that are neither null nor empty. To catch both empty strings and null values you should use <> '' in your SQL statements.

Returning varchars that are not null or empty SQL

I have a column in SQL that is varchar. I need it to return anything with a value.
Example...
select * from students where StudentID <> ''
Is this the correct way of doing it? I've tried is not null but then it returns anything that is empty as well.
Thanks
I would suggest using coalesce:
select * from students where coalesce(StudentID, '') <> ''
This will turn nulls into empty strings and disallow them. This has the added bonus of restricting empty strings as well.
A null is not equal to anything, not even another null, so a simple <> doesnt work.
select * from students where StudentID <> '' AND StudentID IS NOT NULL
You can target both white space and null.
There's something call NOT NULL
SELECT LastName,FirstName,Address FROM Persons WHERE Address IS NOT NULL
Is that helping ?
try this:
select * from students where StudentID is not null
You have to handle the case that it's not null separately because you cannot compare with null-values. They are neither equal nor unequal to any other value(incl. null). NULL means "unknown value", so any comparison with any actual value makes no sense
....
WHERE StudentID IS NOT NULL AND StudentID <> ''
You could use ISNULL(StudentID,'') <> '' (or COALESCE). But i think this is more efficient.
Try using ISNULL()
select * from student where isnull(studentid,'') <> ''

Replacing NULL and empty string within Select statement

I have a column that can have either NULL or empty space (i.e. '') values. I would like to replace both of those values with a valid value like 'UNKNOWN'. The various solutions I have found suggest modifying the value within the table itself. However, this is not an option in this case in that the database is for a 3rd party application that is developed and/or patched very poorly (in reality I think my Rottweiler could have done a better job). I am concerned that modifying the underlying data could cause the application to melt into a smoking hole.
I have attempted variations of the following commands:
COALESCE(Address.COUNTRY, 'United States') -- Won't replace empty string as it is not NULL
REPLACE(Address.COUNTRY, '', 'United States') -- Doesn't replace empty string
ISNULL(Address.COUNTRY, 'United States') -- Works for NULL but not empty string
I know I could use the CASE statement but am hoping there is a much more elegant/efficient solution.
You'll have to trust me when I say I have looked for a solution to my specific issue and have not found an answer. If I have overlooked something, though, kindly show me the lighted path.
Try this
COALESCE(NULLIF(Address.COUNTRY,''), 'United States')
Sounds like you want a view instead of altering actual table data.
Coalesce(NullIf(rtrim(Address.Country),''),'United States')
This will force your column to be null if it is actually an empty string (or blank string) and then the coalesce will have a null to work with.
An alternative way can be this: - recommended as using just one expression -
case when address.country <> '' then address.country
else 'United States'
end as country
Note: Result of checking null by <> operator will return false.
And as documented: NULLIF is equivalent to a searched CASE expression
and COALESCE expression is a syntactic shortcut for the CASE expression.
So, combination of those are using two time of case expression.
For an example data in your table such as combinations of
'', null and as well as actual value than if you want to only actual value and replace to '' and null value by # symbol than execute this query
SELECT Column_Name = (CASE WHEN (Column_Name IS NULL OR Column_Name = '') THEN '#' ELSE Column_Name END) FROM Table_Name
and another way you can use it but this is little bit lengthy and instead of this you can also use IsNull function but here only i am mentioning IIF function
SELECT IIF(Column_Name IS NULL, '#', Column_Name) FROM Table_Name
SELECT IIF(Column_Name = '', '#', Column_Name) FROM Table_Name
-- and syntax of this query
SELECT IIF(Column_Name IS NULL, 'True Value', 'False Value') FROM Table_Name

Any better ways to ascertain whether a column in a table is empty or not?

I have a table say T in SQL Server 2005 database and it has two columns say A and B, which more often than not won't have any values in them.
How to check whether A and B are empty (has all zero length strings) or not?
I have this naive way of doing it -
select count(*) as A_count from T where A <> ''
Let's assume A has data type varchar.
I was wondering whether I can get the same information using a system table, and if so would that be faster than this query?
cheers
Your method is essentially correct, although the wording in your question is imprecise. Does empty include NULL or a non-zero length empty string?
You could handle those cases with:
select count(*) as A_count from T where isnull(rtrim(ltrim(A)), '') <> ''
Also, make sure there is an index on column A.
If your column is nullable, you will have to modify your query as follows:
select count(*) as A_count from T where COALESCE(A, '') <> ''
otherwise you will not count nulls.
If we are talking about zero-length strings, then this is the way that I would do it:
select count(*) as A_count from T where LEN(A) > 0
Keep in mind, however that if A could be null, then these rows will not be caught by either LEN(A) > 0 or LEN(A) = 0, and that you will have to wrap an ISNULL around A in that case.