Postgres: handling null in where clause - sql

Using Birt reporting which allows injecting parameter in a query as follow:
SELECT *
FROM foo
WHERE bar = ?
The question mark comes from a drop down list. Among these values, 'All' can be selected, meaning there are no WHERE clause.
Is there a way to have conditional value in the WHERE clause such as below or an equivalent ?
WHERE
CASE WHEN ? IS NULL
THEN 1=1
ELSE bar = '%'
END

you can try something like:
SELECT *
FROM foo
WHERE COALESCE(bar, '') = COALESCE(?, bar, '')
so, if argument is null - column will be compared with itself, which is almost always returns true, except weird logic around null values, this is why we need coalesce on both sides of equation

Related

SQL: Is there a way for me to call another table.field when my initial table.field = NULL?

Morning All! Essentially, I found out that a potential table.field I'd like to use may not have the information I want, so, I might have to look into a separate field. My below thought process is:
If table.field1 = NULL then pull the value from table.field2. If table.field2 = NULL then state "No Phone"
My current SQL statement in the select, cause it's in a certain format, is:
substring(view_episode_summary_current.patient_home_phone, 1, 3) || ' ' || substring(view_episode_summary_current.patient_home_phone, 5, 8)
Above is let's say table.field1. I'm assuming I'll need to create a CASE statement right? I just didn't know how long it could be?
(case when view_episode_summary_current.patient_home_phone = NULL then table.field2)
But I don't know how to get it to evaluate if table.field2 = null and display the value.
In many databases, you can use coalesce() to implement that kind of logic:
coalesce(t1.field1, t2.field2) as myfield
coalesce() returns the first non-null value across its arguments. So it gives you t1.field1 if it is not null, else it falls back on t2.field2. If both are null, you get a null value as a result.
You could also use a case expression - there is no benefit as compared to colaesce(), but this can handle more complex cases than just nullity checks
case
when t1.field1 is not null then t1.field1
when t2.field2 is not null then t2.field2
end as myfield
case stops on the first branch where the condition is fulfilled. If no branch matches, it returns null - you can put an else branch at the end of your code to return something else.
Note that both techniques requires both fields to have similar data types.
You do not show your actual query so I cannot show how to use that in your code.

How to use conditional different columns in WHERE clause?

I want to use completely different conditions in a WHERE-clause in an SQL Server 2014 query, not just change the parameter.
I have the following clause
WHERE (dbo.SecurityCheckUserInADGroups.CWID = #cwid2) AND (dbo.SecurityCheckUserInDatabaseRoles.Server = #server)
If the variable #cwid2 is NULL or empty I'd like to replace the whole first part of the AND-Statement with
dbo.SecurityCheckLDAPGroupName.DatabaseUserName = #role2
So here not only the parameter but also the column changes.
I tried If, Case and Iif with something like this, but it isn't accepted:
(IIF (LEN(#cwid1) > '0, 'dbo.SecurityCheckUserInADGroups.CWID = #cwid2','dbo.SecurityCheckLDAPGroupName.DatabaseUserName = #role2'))
It keeps telling me "An expression of non-boolean type specified in a context where a condition is expected"
Any ideas how I can solve this?
Just use basic logic:
WHERE ((#cwid <> '' AND dbo.SecurityCheckUserInADGroups.CWID = #cwid2) OR
(COALESCE(#cwid, '') = '' AND dbo.SecurityCheckLDAPGroupName.DatabaseUserName = #role2)
) AND
(dbo.SecurityCheckUserInDatabaseRoles.Server = #server)
The most general solution would be
Where (#var is null and col1=val1)
Or (#var is not null and col2=val2)
Because query optimizers can sometimes choke on OR, I tend to look for other solutions when performance could be an issue (large data sets, etc.) but the above might be worth trying first.
If you do need something more specific, the trick to iif logic is that it returns a value to compare, not a predicate to evaluate. You could do something like
Where col1 = iif(#var is null, val1, col1)
And col2 = iif(var is null, col2, val2)
The idea here is that your "don't care" cases - like the value of col2 when var is null - resolve as "always true". But there are cases (like when col1 or col2 could be NULL) where this specific solution Will fail.
Which is why the first approach is the most general
WHERE CASE WHEN ISNULL(#cwid2,'') <> '' THEN
dbo.SecurityCheckUserInADGroups.CWID = #cwid2 ELSE
dbo.SecurityCheckLDAPGroupName.DatabaseUserName = #role2
END
AND dbo.SecurityCheckUserInDatabaseRoles.Server = #server

Oracle : IN and OR

I've a scenrio which process many data in Oracle database. In some cases, the variable Sec_email will contain many values and in some cases Sec_email will contain null or ' '.
so can please any one tell me how to write a query for this?
I tried with
(C.SECONDARY_EMAIL IN ('?,?') OR '' = '' )
where C is the Client table.
When I use this i get the count as 0.
You can perform a not null check before the IN comparison like
Sec_email is not null and C.SECONDARY_EMAIL IN (...
One obvious problem is that Oracle (by default) treats empty strings as NULL. So: '' = '' is the same as NULL = NULL, which is never true.
Arrgh.
In any case, you are probably constructing the query, so use is null instead:
(C.SECONDARY_EMAIL IN ('?,?') OR '' IS NULL
I think the real problem, though, is the first comparison. The IN list has one element with a constant, not two (but perhaps that is your intention). If you want to put a variable number of values for comparison, one method uses regular expressions. For instance:
C.SECONDARY_EMAIL REGEXP_LIKE '^val1|val2|val3$' or '' IS NULL
If you would like to get a list of values when some of them is null you should use:
("some other conditions" OR C.SECONDARY_EMAIL IS NULL)
The question is if it is not null and not ' ' value what you are expecting, if it should be some king of
pattern you should use regular expression:
regexp_like(C.SECONDARY_EMAIL, '^(.+?[,]+?)+$')
Also, if you have a few conditions in where clause use should use brackets to group you conditions null check and another one.
All conditions i this case will be divided by OR.
(C.SECONDARY_EMAIL IS NULL OR regexp_like(C.SECONDARY_EMAIL, '^(.+?[,]+?)+$'))
or
(C.SECONDARY_EMAIL IS NULL OR regexp_like(C.SECONDARY_EMAIL, '^(.+?[,]+?)+$')
OR C.SECONDARY_EMAIL = ' ')

Is there a way to make NULL behave like 0 (zero) or like an empty string in SQL?

Assume a sqlite database with an integer column.
Now, it tends to happen that the integer field contains NULL values (=unset) as well.
I would like to interpret NULL values as zero (0) when doing queries on that field.
Is there a way to tell sqlite that I like NULL handled like 0 in this case, especially when I do comparisons using a SELECT statement?
Since I construct the queries dynamically in C-like code, I like to be able to write something like this:
query = "SELECT * FROM tbl WHERE intField=" + IntToStr(anIntValue)
Currently, I work around this with code as follow, which I like to avoid:
if (anIntValue == 0) {
query = "SELECT * FROM tbl WHERE intField IS NULL OR intField=0"
} else {
query = "SELECT * FROM tbl WHERE intField=" + IntToStr(anIntValue)
}
Maybe there's an operator I can use in the query that converts NULLs to other values I specify?
Of course, another way would be to make sure one never ends up with NULL values in that field, but one might want to be able to tell when the value hasn't been set at all yet, so I like to be able to keep the NULL values in the database.
In Standard SQL this is called COALESCE:
COALESCE(col, 0)
Why using a proprietary extension like IFNULL/NVL if there's a Standard which is supported by every DBMS?
please, try ifnull function, see doc at http://www.sqlite.org/lang_corefunc.html#ifnull
You can use IFNULL
or
CASE WHEN fieldname IS NULL THEN 0 ELSE fieldname END
This works the same as isnull(fieldname, 0)
You can read more here
Although you could use null coalesce functionality of your RDBMS, a universal approach exists that lets you treat NULLs as zeros in a condition, like this:
String val = IntToStr(anIntValue)
"SELECT * FROM tbl WHERE intField=" + val + " OR (0="+ val+" AND intField IS NULL)"

Sql Server: CASE Statement does unexpected behavior when comparing to NULL

Given:
The following Select statement:
select case NULL
when NULL then 0
else 1
end
Problem:
I'm expecting this to return 0 but instead it returns 1. What gives?
Generally speaking, NULL is not something you should attempt to compare for equality, which is what a case statement does. You can use "Is NULL" to test for it. There is no expectation that NULL != NULL or that NULL = NULL. It's an indeterminate, undefined value, not a hard constant.
-- To encompass questions in the comments --
If you need to retrieve a value when you may encounter a NULL column, try this instead:
Case
When SomeColumn IS NULL
Then 0
Else 1
End
I believe that should work. As far as your original post is concerned:
Select Case NULL
When NULL then 0 // Checks for NULL = NULL
else 1 // NULL = NULL is not true (technically, undefined), else happens
end
The trouble is that your Case select automatically attempts to use equality operations. That simply doesn't work with NULL.
I was going to add this as a comment to Aaron's answer, but it was getting too long, so I'll add it as another (part of the) answer.
The CASE statement actually has two distinct modes, simple and searched.
From BOL:
The CASE expression has two formats:
The simple CASE expression compares an expression to a set of simple expressions to determine the result.
The searched CASE expression evaluates a set of Boolean expressions to determine the result.
When the simple CASE (your example) does what it describes as comparison it does an equality comparison - i.e. =
This is clarified in the later documentation:
The simple CASE expression operates by comparing the first expression
to the expression in each WHEN clause for equivalency. If these
expressions are equivalent, the expression in the THEN clause will be
returned.
Allows only an equality check.
Because anything = NULL is always false in ANSI SQL (and if you didn't know this, you need to read up on NULLs in SQL more generally, particularly also with the behavior in the other searched comparison - WHERE x IN (a, b, c)), you cannot use NULL in a simple case and have it ever be compared to a value, with a NULL either in the initial expression or in the list of expressions to be compared against.
If you want to check for NULL, you will have to use an IF/ELSE construct or the searched CASE with a full expression.
I agree that it's kind of unfortunate there is no version which supports an IS comparison to make it easier to write:
select case colname
when IS NULL then 0
else 1
end
Which would make writing certain long CASE statements easier:
select case colname
when IS NULL then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But that's just wishful thinking...
An option is to use ISNULL or COALESCE:
select case COALESCE(colname, 999999) -- 999999 is some value never used
when 999999 then ''
when 1 then 'a'
when 2 then 'b'
when 3 then 'c'
when 4 then 'd'
else 'z'
end
But it isn't always a great option.
In addition to the other answers, you need to change the syntax for CASE slightly to do this:
SELECT CASE
WHEN NULL IS NULL THEN 0
ELSE 1
END;
Using the value in your syntax implicitly uses an equals comparison. NULL is unknown, and so is NULL = NULL, so with your current code you will always get zero 1 (geez I did it too).
To get the behavior you want, you can use SET ANSI_NULLS ON; however note that this can change other code in ways you may not be able to predict, and the setting is deprecated - so it will stop working at all in a future version of SQL Server (see this SQL Server 2008 doc).
You need to use the IS NULL operator. Standard comparison operators do not work with NULL.
Check out these MSDN articles about Null that may be useful:
IS [NOT] NULL (Transact-SQL)
Null Values