IN Clause with NULL or IS NULL - sql

Postgres is the database
Can I use a NULL value for a IN clause? example:
SELECT *
FROM tbl_name
WHERE id_field IN ('value1', 'value2', 'value3', NULL)
I want to limit to these four values.
I have tried the above statement and it doesn't work, well it executes but doesn't add the records with NULL id_fields.
I have also tried to add a OR condition but this just make the query run and run with no end in sight.
SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND id_field IN ('value1', 'value2', 'value3')
OR id_field IS NULL
Any suggestions?

An in statement will be parsed identically to field=val1 or field=val2 or field=val3. Putting a null in there will boil down to field=null which won't work.
(Comment by Marc B)
I would do this for clairity
SELECT *
FROM tbl_name
WHERE
(id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL)

Your query fails due to operator precedence. AND binds before OR!
You need a pair of parentheses, which is not a matter of "clarity", but pure logic necessity.
SELECT *
FROM tbl_name
WHERE other_condition = bar
AND another_condition = foo
AND (id_field IN ('value1', 'value2', 'value3') OR id_field IS NULL);
The added parentheses prevent AND binding before OR. If there were no other WHERE conditions (no AND) you would not need additional parentheses. The accepted answer is misleading in this respect.

SELECT *
FROM tbl_name
WHERE coalesce(id_field,'unik_null_value')
IN ('value1', 'value2', 'value3', 'unik_null_value')
So that you eliminate the null from the check. Given a null value in id_field, the coalesce function would instead of null return 'unik_null_value', and by adding 'unik_null_value to the IN-list, the query would return posts where id_field is value1-3 or null.

The question as answered by Daniel is perfctly fine. I wanted to leave a note regarding NULLS. We should be carefull about using NOT IN operator when a column contains NULL values. You won't get any output if your column contains NULL values and you are using the NOT IN operator. This is how it's explained over here http://www.oraclebin.com/2013/01/beware-of-nulls.html , a very good article which I came across and thought of sharing it.

Note: Since someone claimed that the external link is dead in Sushant Butta's answer I've posted the content here as a separate answer.
Beware of NULLS.
Today I came across a very strange behaviour of query while using IN and NOT IN operators. Actually I wanted to compare two tables and find out whether a value from table b existed in table a or not and find out its behavior if the column containsnull values. So I just created an environment to test this behavior.
We will create table table_a.
SQL> create table table_a ( a number);
Table created.
We will create table table_b.
SQL> create table table_b ( b number);
Table created.
Insert some values into table_a.
SQL> insert into table_a values (1);
1 row created.
SQL> insert into table_a values (2);
1 row created.
SQL> insert into table_a values (3);
1 row created.
Insert some values into table_b.
SQL> insert into table_b values(4);
1 row created.
SQL> insert into table_b values(3);
1 row created.
Now we will execute a query to check the existence of a value in table_a by checking its value from table_b using IN operator.
SQL> select * from table_a where a in (select * from table_b);
A
----------
3
Execute below query to check the non existence.
SQL> select * from table_a where a not in (select * from table_b);
A
----------
1
2
The output came as expected. Now we will insert a null value in the table table_b and see how the above two queries behave.
SQL> insert into table_b values(null);
1 row created.
SQL> select * from table_a where a in (select * from table_b);
A
----------
3
SQL> select * from table_a where a not in (select * from table_b);
no rows selected
The first query behaved as expected but what happened to the second query? Why didn't we get any output, what should have happened? Is there any difference in the query? No.
The change is in the data of table table_b. We have introduced a null value in the table. But how come it's behaving like this? Let's split the two queries into "AND" and "OR" operator.
First Query:
The first query will be handled internally something like this. So a null will not create a problem here as my first two operands will either evaluate to true or false. But my third operand a = null will neither evaluate to true nor false. It will evaluate to null only.
select * from table_a whara a = 3 or a = 4 or a = null;
a = 3 is either true or false
a = 4 is either true or false
a = null is null
Second Query:
The second query will be handled as below. Since we are using an "AND" operator and anything other than true in any of the operand will not give me any output.
select * from table_a whara a <> 3 and a <> 4 and a <> null;
a <> 3 is either true or false
a <> 4 is either true or false
a <> null is null
So how do we handle this? We will pick all the not null values from table table_b while using NOT IN operator.
SQL> select * from table_a where a not in (select * from table_b where b is not null);
A
----------
1
2
So always be careful about NULL values in the column while using NOT IN operator.
Beware of NULL!!

I know that is late to answer but could be useful for someone else
You can use sub-query and convert the null to 0
SELECT *
FROM (SELECT CASE WHEN id_field IS NULL
THEN 0
ELSE id_field
END AS id_field
FROM tbl_name) AS tbl
WHERE tbl.id_field IN ('value1', 'value2', 'value3', 0)

Null refers to an absence of data. Null is formally defined as a value that is unavailable, unassigned, unknown or inapplicable (OCA Oracle Database 12c, SQL Fundamentals I Exam Guide, p87).
So, you may not see records with columns containing null values when said columns are restricted using an "in" or "not in" clauses.

Related

How to perform IF ELSE THEN T-SQL?

Is it possible to perform IF ELSE THEN in SQL Server ?
For example I want to perform IF my result of query is NOT NULL (My row is exist). It will continue to THEN statement
ELSE if my result of query is NULL (My row is doesn't exist), it will continue to another THEN statement
For T-SQL Example, this is just dummy SQL script
IF (SELECT * FROM TABLE_A) IS NOTNULL THEN
(INSERT INTO TABLE_B)
ELSE
(DIDN'T PERFORM ANY QUERY)
Thank you
You could check if the table returns any rows and then perform SELECT INTO operation
IF EXISTS (SELECT 1 FROM TABLE_A)
BEGIN
SELECT * INTO TABLE_B FROM TABLE_A
END;
You could use your SELECT statement in the WHERE clause of your INSERT, like so:
INSERT INTO TABLE_B(...)
SELECT ...
FROM ...
WHERE EXISTS(SELECT * FROM TABLE_A);
and then test wether anything was inserted with IF ##ROWCOUNT > 0 THEN.
Assuming you just want to insert specific rows from A into B, then you can use:
INSERT INTO TABLE_B ( . . . ) -- list the columns here
SELECT . . .
FROM TABLE_A;
If there are no rows, then nothing gets inserted. It is that simple.
Actually, it is simpler than that. Using IF introduces race conditions in your code. The TABLE_A could change between the execution of the IF and the INSERT, so the code is not thread-safe. This code does not have that problem.

compare data between 2 table

Hey i have a requirement to compare two tables of same structure.
Table1
EmpNO - Pkey
EmpName
DeptName
FatherName
IssueDate
ValidDate
I need to pass the EMPNO as parameter and I need to compare whether any of the column get changes? and return YES OR NO value.
can I able to do that using a PL/SQL Funcation? I was thinking of using the CONCAT in-build function to do that.
I'm trying the below one
Table1Concat = Select CONCAT(Column1.....6) from tbale1 where emp_no= in_empno;
Table2Concat = Select CONCAT(Column1.....6) from tbale2 where emp_no= in_empno;
IF(Table1Concat<>Table2Concat ) THEN return data_changed :='YES';
else data_changed :='NO';
END;
If you only want to detect whether any value is different then ...
select count(*)
from (select * from table1 where emp_no = my_emp_no
union
select * from table2 where emp_no = my_emp_no
)
If it returns 1 then the rows are the same, if it returns 2 then there is a difference.
The columns must be in the same order for this to work, or you'll have to list out all the column names in the order in which they match.
If you wanted to do this in bulk for a great many rows then you'd most likely use a different solution, s do not loop through every emp_no running this code for each one.
For bulk data where all emp_id's are present in both tables, use a query of the form:
select table1.emp_no,
case when table1.column1 = table2.column1 and
table2.column2 = table2.column2 and
table2.column3 = table2.column3 and
...
then 'Yes'
else 'No
end columns_match
from table1
join table2 on table1.emp_no = table2.emp_no
You can insert this result directly into a logging table.
Take care of null values though. "any_value = null" is never true, and "any_value != Null" is also never true, so you might need to add logic to take care of cases where one or both values are null.

Excluding a Null value returns 0 rows in a sub query

I'm trying to clean up some data in SQL server and add a foreign key between the two tables.
I have a large quantity of orphaned rows in one of the tables that I would like to delete. I don't know why the following query would return 0 rows in MS SQL server.
--This Query returns no Rows
select * from tbl_A where ID not in ( select distinct ID from tbl_B
)
When I include IS NOT NULL in the subquery I get the results that I expect.
-- Rows are returned that contain all of the records in tbl_A but Not in tbl_B
select * from tbl_A where ID not in ( select distinct ID from tbl_B
where ID is not null )
The ID column is nullable and does contain null values. IF I run just the subquery I get the exact same results except the first query returns one extra NULL row as expected.
This is the expected behavior of the NOT IN subquery. When a subquery returns a single null value NOT IN will not match any rows.
If you don't exclusively want to do a null check, then you will want to use NOT EXISTS:
select *
from tbl_A A
where not exists (select distinct ID
from tbl_B b
where a.id = b.id)
As to why the NOT IN is causing issues, here are some posts that discuss it:
NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL
NOT EXISTS vs NOT IN
What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?
Matching on NULL with equals (=) will return NULL or UNKNOWN as opposed to true/false from a logic standpoint. E.g. see http://msdn.microsoft.com/en-us/library/aa196339(v=sql.80).aspx for discussion.
If you want to include finding NULL values in table A where there is no NULL in table B (if B is the "parent" and A is the "child" in the "foreign key" relationship you desire) then you would need a second statement, something like the following. Also I would recommend qualifying the ID field with a table prefix or alias since the field names are the same in both tables. Finally, I would not recommend having NULL values as the key. But in any case:
select * from tbl_A as A where (A.ID not in ( select distinct B.ID from tbl_B as B ))
or (A.ID is NULL and not exists(select * from tbl_B as B where B.ID is null))
The problem is the non-comparability of nulls. If you are asking "not in" and there are nulls in the subquery it cannot say that anything anything is definitely not in becuase it is looking at those nulls as "unknown" and so the answer is always "unknown" in the three value logic that SQL uses.
Now of course that is all assuming you have ANSI_NULLS ON (which is the default) If you turn that off then suddenly NULLS become comparable and it will give you results, and probably the results you expect.
If the ids are never negative, you might consider something like:
select *
from tbl_A
where coalesce(ID, -1) not in ( select distinct coalesce(ID, -1) from tbl_B )
(Or if id is a string, use something line coalesce(id, '<null>')).
This may not work in all cases, but it has the virtue of simplicity on the coding level.
You probably have ANSI NULLs switched off. This compares null values so null=null will return true.
Prefix the first query with
SET ANSI_NULLS ON
GO

Can the "IN" operator use LIKE-wildcards (%) in Oracle?

I have searched this question, and found an answer in MySQL but this is one of those incidents where the statement fails to cross over into Oracle.
Can I use wildcards in "IN" MySQL statement?
pretty much sums up my question and what I would like to do, but in Oracle
I would like to find the legal equivalent of
Select * from myTable m
where m.status not in ('Done%', 'Finished except%', 'In Progress%')
Thanks for any help
Select * from myTable m
where m.status not like 'Done%'
and m.status not like 'Finished except%'
and m.status not like 'In Progress%'
It seems that you can use regexp too
WHERE NOT REGEXP_LIKE(field, '^Done|^Finished')
I'm not sure how well this will perform though ... see here
This appears to fit what you are looking for: https://forums.oracle.com/forums/thread.jspa?threadID=2140801
Basically, you will need to use regular expressions as there appears to be nothing built into oracle for this.
I pulled out the example from the thread and converted it for your purposes. I suck at regex's, though, so that might need tweaked :)
SELECT *
FROM myTable m
WHERE NOT regexp_like(m.status,'((Done^|Finished except^|In Progress^)')
Not 100% what you were looking for, but kind of an inside-out way of doing it:
SQL> CREATE TABLE mytable (id NUMBER, status VARCHAR2(50));
Table created.
SQL> INSERT INTO mytable VALUES (1,'Finished except pouring water on witch');
1 row created.
SQL> INSERT INTO mytable VALUES (2,'Finished except clicking ruby-slipper heels');
1 row created.
SQL> INSERT INTO mytable VALUES (3,'You shall (not?) pass');
1 row created.
SQL> INSERT INTO mytable VALUES (4,'Done');
1 row created.
SQL> INSERT INTO mytable VALUES (5,'Done with it.');
1 row created.
SQL> INSERT INTO mytable VALUES (6,'In Progress');
1 row created.
SQL> INSERT INTO mytable VALUES (7,'In progress, OK?');
1 row created.
SQL> INSERT INTO mytable VALUES (8,'In Progress Check Back In Three Days'' Time');
1 row created.
SQL> SELECT *
2 FROM mytable m
3 WHERE +1 NOT IN (INSTR(m.status,'Done')
4 , INSTR(m.status,'Finished except')
5 , INSTR(m.status,'In Progress'));
ID STATUS
---------- --------------------------------------------------
3 You shall (not?) pass
7 In progress, OK?
SQL>
Somewhat convoluted, but:
Select * from myTable m
join (SELECT a.COLUMN_VALUE || b.COLUMN_VALUE status
FROM (TABLE(Sys.Dbms_Debug_Vc2coll('Done', 'Finished except', 'In Progress'))) a
JOIN (Select '%' COLUMN_VALUE from dual) b on 1=1) params
on params.status like m.status;
This was a solution for a very unique problem, but it might help someone. Essentially there is no "in like" statement and there was no way to get an index for the first variable_n characters of the column, so I made this to make a fast dynamic "in like" for use in SSRS.
The list content ('Done', 'Finished except', 'In Progress') can be variable.
The closest legal equivalent to illegal syntax mentioned in question is:
select * from myTable m
where not exists (
select 1
from table(sys.ku$_vcnt('Done', 'Finished except', 'In Progress')) patterns
where m.status like patterns.column_value || '%'
)
Both mine and #Sethionic's answer make possible to list patterns dynamically (just by choosing other source than auxiliar sys.whatever table).
Note, if we had to search pattern inside string (rather than from the beginning) and database contained for example status = 'Done In Progress', then
my solution (modified to like '%' || patterns.column_value || '%') would still generate one row for given record, whileas
the #Sethionic's solution (modified to another auxiliar join before a) would produce multiple rows for each pattern occurence.
Not judging which is better, just be aware of differences and choose which better fits your need.

Select rows where column is null

How do you write a SELECT statement that only returns rows where the value for a certain column is null?
Do you mean something like:
SELECT COLUMN1, COLUMN2 FROM MY_TABLE WHERE COLUMN1 = 'Value' OR COLUMN1 IS NULL
?
I'm not sure if this answers your question, but using the IS NULL construct, you can test whether any given scalar expression is NULL:
SELECT * FROM customers WHERE first_name IS NULL
On MS SQL Server, the ISNULL() function returns the first argument if it's not NULL, otherwise it returns the second. You can effectively use this to make sure a query always yields a value instead of NULL, e.g.:
SELECT ISNULL(column1, 'No value found') FROM mytable WHERE column2 = 23
Other DBMSes have similar functionality available.
If you want to know whether a column can be null (i.e., is defined to be nullable), without querying for actual data, you should look into information_schema.
Use Is Null
select * from tblName where clmnName is null
You want to know if the column is null
select * from foo where bar is null
If you want to check for some value not equal to something and the column also contains null values you will not get the columns with null in it
does not work:
select * from foo where bar <> 'value'
does work:
select * from foo where bar <> 'value' or bar is null
in Oracle (don't know on other DBMS) some people use this
select * from foo where NVL(bar,'n/a') <> 'value'
if I read the answer from tdammers correctly then in MS SQL Server this is like that
select * from foo where ISNULL(bar,'n/a') <> 'value'
in my opinion it is a bit of a hack and the moment 'value' becomes a variable the statement tends to become buggy if the variable contains 'n/a'.
select Column from Table where Column is null;
select * from tableName where columnName is null
For some reasons IS NULL may not work with some column data type. I was in need to get all the employees that their English full name is missing, I've used:
SELECT emp_id, Full_Name_Ar, Full_Name_En
FROM employees
WHERE Full_Name_En = '' or Full_Name_En is null