Use like '%' and match NULL values with NUMBER columns - sql

This question is almost exactly like mine but none of the answers work with my case.
If it was my question I'd slightly edit it to make it a different question. This question is thus different from the linked one.
Here's the problem: I want a way to match any non-null value ('%') AND null values.
The thing is:
I'm using oracle so I can't use IsNull
Some columns are NUMBERs, which means I can't use COALESCE(column, ' '). (ORA-00932: inconsistent datatypes: expected NUMBER got CHAR). However, like '%' and like '2118' do work on NUMBER columns.
None of the answers apply to this problem because you can't make a null into an empty string when the column is a NUMBER.
How could I do to achieve this?
Some context:
My procedure takes a lot of parameters, and does a select with all of them. They can all have a value or be null, so if they're null they're replaced with '%'.
That way, the procedure does :
where t.col1 like param1
and t.col2 like param2
...
Most of the times, only one or two parameters is not null. For the others parameters, the procedure needs to match on every row.
But when the value is null, like '%' doesn't match the row. I'm looking for a way to match anything when param x is empty (so paramx = '%')

My procedure takes a lot of parameters, and does a select with all of them. They can all have a value or be null, so if they're null they're replaced with '%'.
That seems like you're making life hard for yourself. Leave them null, then do:
where (param1 is null or t.col1 like param1)
and (param2 is null or t.col2 like param2)
If param1 (the procedure argument; life is simpler when your parameter/variable names and column names are different... so I've changed the column names to make it a bit clearer) is null it is basically ignored* and all rows pass that part of the filter, whether the column value is null or not null. If param2 is not null then the is null check for that fails and only rows with (not-null) column values that match param2 value meet that part of the filter.
* Conditions in an or can be evaluated in any order; putting the is null check first doesn't necessarily mean the like won't be evaluated - but the optimiser is pretty smart about that sort of thing

If you want to match a specific value and NULL, you can use OR:
where col = <specific value> or col is null

In Oracle NVL can be used instead of ISNULL
IF NVL(aNumberColumn,-1) = -1 THEN
---whatever
END IF;

Oracle automatically converts NUMBER to VARCHAR2 for like-conditions. So what you have todo is do that yourself so you can use coalesce:
COALESCE(TO_CHAR(column), ' ') like '%'

The proposals from other answers based on OR or NVL/ COALESCE are "elegant" and simple, but as a rule they inhibit the index access, which is the most important thing.
You may step down to use dynamic SQL to address the optional parameter problem - which is your case. If a parameter is not passed (it is NULL) - simple ignore it.
So for example with two parameters, if both parameters are passed, generate following SQL
select * from tab t
where t.col1 like :param1
and t.col2 like :param2
If only parameter 1 is given, generate this SQL:
select * from tab t
where t.col1 like :param1
With no parameter you will end with
select * from tab t
Technically it is preferable to have in all SQL statements the same number of bind variables, which is not the case in the above proposal. See this answer for detailed explanation of the trick popularized by Tom Kyte to preserve the number of bind variable with optional parameters.
For example the second statement with only parameter 1 would yield following SQL
select * from tab t
where t.col1 like :param1
and (1=1 or t.col2 like :param2)
The shortcut logik of 1=1(which is TRUE) eliminates the second part of the predicate, but the bind variable is still used, so the number of the bind variables remains constant.
The big advantage is a fine index range access of this query

Related

Oracle DB LIKE query on NULL values

This question is about Oracle DB. I want to know how Oracle DB query LIKE clause works on NULL values.
Select * From table_name where column_name like 'text%'
In above query, how the Oracle db treat to rows with null value for column 'column_name'? Also how about 'NOT LIKE'.
Also, I observed that rows having NULL values are not selected for the following query.
Select * From table_name where column_name NOT LIKE 'text%' .
I don't know why rows having NULL values for the column are not in results even though they are null and hence not like 'text%' .
NULL values basically fail all comparisons. The general idea is that NULL means "I don't know what the value is". So, when you use like with the pattern 'text%', the answer is "I don't know what the value is". It is NULL.
And if you use not like, the answer is the same "I don't know what the result is".
That is how NULLs work. Even with like and not like. Even with Oracle.
First one,
When you search for column_name like 'text%', db search for string that starts with "text" not other string, it doesn't matter what will come after the text. It could be anything like text123,text stack etc.
Second one,
When you search for NOT LIKE 'text%', db search for all the columns that should not be started with text, it the column value have text it will not be in the result. it is like "atext", it will be appear in the search results.
So in both condition NULL values never match so they don't come in the results.
Hope it will help.
Try this,
SELECT *
FROM table_name
WHERE NVL(column_name,1) NOT LIKE NVL('',2) -- '' OR NULL you can use
Try this,
SELECT *
FROM table_name
WHERE NVL(column_name,1) NOT LIKE NVL('',2) -- '' OR NULL you can use

SQL WHERE is anything

I'm working on a database query via a search bar and would like it to sometimes yield all results (depending on what is inputted)
I know that for SELECT you can use * in order to select all columns. Is there similar SQL syntax: i.e. WHERE name IS * to essentially always be true?
Edit to clarify:
The nature of the clause is that a variable is used to set the name (I'm actually not able to change the clause, that was made clear). i.e. WHERE name IS [[inputName]] (inputName is the decided by the search bar)
WHERE ISNULL(name, '') = ISNULL(name, '')
(assuming that 'name' is of a string type)
Just make the column reference itself. However, if this is the only goal of your query, why are you against omitting the WHERE clause?
If you want to return all results in a SQL statement, you can simply omit the WHERE clause:
SELECT <* or field names> FROM <table>;
You should use WHERE only when you want to filter your data on a certain field. In your case you just don't want to filter at all.
Actually you don't need WHERE clause at all in this situation. But if you insist then you should write your predicate so it always returns true. This can be done many ways:
Any predicate like:
WHERE 1=1
With column:
WHERE name = name OR name is null
With LIKE:
WHERE name LIKE '%' OR name is null
With passed parameter:
WHERE name = #name OR #name is null
You can think of more of course. But I think you need the last one. Pass NULL from app layer if you want all rows.

PL/SQL Oracle condition equals

I think I'm encountering a fairly simple problem in PL/SQL on an Oracle Database(10g) and I'm hoping one of you guys can help me out.
I'm trying to explain this as clear as possible, but it's hard for me.
When I try to compare varchar2 values of 2 different tables to check if I need to create a new record or I can re-use the ID of the existing one, the DB (or I) compares these values in a wrong way. All is fine when both the field contain a value, this results in 'a' = 'a' which it understands. But when both fields are NULL (or '' which Oracle will turn into NULL) it can not compare the fields.
I found a 'solution' to this problem but I'm certain there is a better way.
rowTable1 ROWTABLE1%ROWTYPE;
iReUsableID INT;
SELECT * INTO rowTable1
FROM TABLE1
WHERE TABLE1ID = 'someID';
SELECT TABLE2ID INTO iReUsableID
FROM TABLE2
WHERE NVL(SOMEFIELDNAME,' ') = NVL(rowTable1.SOMEFIELDNAME,' ');
So NVL changes the null value to ' ' after which it will compare in the right way.
Thanks in advance,
Dennis
You can use LNNVL function (http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions078.htm) and reverse the condition:
SELECT TABLE2ID INTO iReUsableID
FROM TABLE2
WHERE LNNVL(SOMEFIELDNAME != rowTable1.SOMEFIELDNAME);
Your method is fine, unless one of the values could be a space. The "standard" way of doing the comparison is to explicitly compare to NULL:
WHERE col1 = col2 or col1 is null and col2 is null
In Oracle, comparisons on strings are encumbered by the fact that Oracle treats the empty string as NULL. This is a peculiarity of Oracle and not a problem in other databases.
In Oracle (or any RDBMS I believe), one NULL is not equal to another NULL. Therefore, you need to use the workaround that you have stated if you want to force 2 NULL values to be considered the same. Additionally, you might want to default NULL values to '' (empty) rather than ' ' (space).
From Wikipedia (originally the ISO spec, but I couldn't access it):
Since Null is not a member of any data domain, it is not considered a "value", but rather a marker (or placeholder) indicating the absence of value. Because of this, comparisons with Null can never result in either True or False, but always in a third logical result, Unknown.
As mentioned by Jan Spurny, you can use LNNVL for comparison. However, it would be wrong to say that a comparison is actually being made when both values being compared are NULL.
This is indeed a simple and usable way to compare nulls.
You cannot compare NULLS directly since NULL is not equal NULL.
You must provide your own logic who you would like to compare, what you've done with NVL().
Take in mind, you are treating NULLS as space, so ' ' in one table would be equal to NULL in another table in your case.
There are some other ways (e.g. LNNVL ) but they are not some kind of a "better" way, I think.

Sql Server Contains

I need to match on a partial string but can't turn full-text indexing on so can't use contains. I've looked at Levenstein's function for determining the distance between two strings but I'm not looking for fuzzy matching but that every character in the column exists in the string.
I.e. If the string being passed is something like AB_SYS_20120430.TXT I want to match on any columns containing AB_SYS. The like predicate isn't getting me there. I really need the equivalent of the .NET contains feature but as mentioned turning on full text indexing isn't an option to be turned on. Thought I would see if there were any other possible work arounds.
Are you looking for the LIKE function?
http://www.w3schools.com/sql/sql_like.asp
... WHERE MyColumn LIKE '%AB_SYS%'
That may not be optimal, but it seems like it answers your question... If you can search from only the left or right side that could further optimize.
That is functionally similar to String.Contains
http://msdn.microsoft.com/en-us/library/dy85x1sa.aspx
EDIT: How will you parse the input text into the "relevant" substring?
EDIT: To search the same LIKE condition but reverse, from your partial column to the complete literal, simply append the wildcard characters:
... WHERE 'AB_SYS_20120430.TXT' LIKE '%' + MyColumn + '%'
EDIT: You have suggested that you can't get it to work. If you add the schema do your question then I can help you further but consider this:
You have a table called MyTable
In that table there is a column called MyColumn
Some rows in that table have the data 'AB_SYS' in MyColumn
Given the parameter 'AB_SYS_20120430.TXT' you want to return all matching rows
CREATE PROCEDURE MyTestProcedure
#pFullNameString nvarchar(4000) = '' -- parameter passed in, like AB_SYS_20120430.TXT
AS
BEGIN
SELECT
*
FROM
MyTable
WHERE
#pFullNameString LIKE '%' + MyTable.[MyColumn] + '%'
END
GO
You could use CHARINDEX
WHERE CHARINDEX(StringToCheckFor, StringToCheckIn) > 0

How to generate WHERE condition based on parameter values which are not blank/null in stored procedure?

I have stored procedure where I am performing search operation, the procedure takes 10 input parameters and returns rows found for those parameters.
I am using the LIKE search operator, but my problem is there are possibilities that only few parameters are passed with values, the rest can be blank or null. I want to exclude the blank/null parameter values from my query's WHERE condition, please suggest me.
Thanks in advance
SP
select *
from YourTable
where (#Param1 is null or Field1 like #Param1)
and (#Param2 is null or Field2 like #Param2)
You can use any condition instead of like
select *
from Table
where isnull(#Field1,Field1) = Field1
and isnull(#Field2,Field2) = Field2
Using the same technique, you can test for blank before doing the select part of your query and convert it to null before the select (it would then cover your blank and null cases)