tags:

views:

92

answers:

5

I have a stored procedure with a parameter name which I want to use in a where clause to match the value of a column i.e. something like

where col1 = name

Now of course this fails to match null to null because of the way null works. Do I need to do

where ((name is null and col1 is null) or col1 = name)

in situations like this or is there a more concise way of doing it?

+2  A: 

What you have done is correct. There is a more concise way, but it isn't really better:

where nvl(col1,'xx') = nvl(name,'xx')

The trouble is, you have to make sure that the value you use for nulls ('xx' is my example) couldn't actually be a real value in the data.

Tony Andrews
+3  A: 

I think your own suggestion is the best way to do it.

oocce
+3  A: 

If col1 is indexed, it would be best (performance-wise) to split the query in two:

SELECT  *
FROM    mytable
WHERE   col1 = name
UNION ALL
SELECT  *
FROM    mytable
WHERE   name IS NULL AND col1 IS NULL

This way, Oracle can optimize both queries independently, so the first or second part won't be actually executed depending on the name passed being NULL or not.

Oracle, though, does not index NULL values of fields, so searching for a NULL value will always result in a full table scan.

If your table is large, holds few NULL values and you search for them frequently, you can create a function-based index:

CREATE INDEX ix_mytable_col1__null ON mytable (CASE WHEN col1 IS NULL THEN 1 END)

and use it in a query:

SELECT  *
FROM    mytable
WHERE   col1 = name 
UNION ALL
SELECT  *
FROM    mytable
WHERE   CASE WHEN col1 IS NULL THEN 1 END = CASE WHEN name IS NULL THEN 1 END
Quassnoi
null values indexing only in bitmap indexes ...
walla
The optimizer won't know if the parameter (which becomes a bind variable) is null or not, so it will run both queries - probably slower as it will likely involve a full table scan AND an indexed read (or second full table scan!)
Tony Andrews
The optimizer won't, but the query engine will. The second query will show up in the plan but won't be really executed. Just try it.
Quassnoi
Thanks, I learned something new!
Tony Andrews
+4  A: 

You can use decode function in the following fashion:

where decode(col1, name, 0) is not null

Cite from SQL reference:

In a DECODE function, Oracle considers two nulls to be equivalent.

andr
That's something I never knew about `DECODE`. But shouldn't that be `where decode(col1,name,0,1) = 0` or something?
Adam Hawkes
@Adam Hawkes in your example you've specified the 4-th argument of `decode` - default value if no matches have been found. If the 4-th argument is not specified `decode` returns `null`, hence our code samples are identical if we concern the author's question: compare `null` values.
andr
A: 

Keep it the way you have it. It's more intuitive, less buggy, works in any database, and is faster. The concise way is not always the best. See http://stackoverflow.com/questions/3678436/plsql-what-is-the-simplest-expression-to-test-for-a-changed-value-in-an-oracle/3682004#3682004

jonearles