SELECT * FROM Employees WHERE NULL IS NULL; SELECT * FROM Employees WHERE NULL = NULL; - sql

I have recently started learning oracle and sql.
While learning I encountered a couple of queries which my friend was asked in an interview.
SELECT *
FROM Employees
WHERE NULL IS NULL;
this query yields all the rows in the Employees table.
As for as I have understood Oracle searches data in columns, so, NULL, is it treated as a column name here?
Am I correct when I say that Oracle searches for data in columns?
How come Oracle gives all the rows in this query?
In WHERE clause, is it not must that the left hand side of a condition be a COLUMN NAME?
Shouldn't it throw an error?
SELECT *
FROM Employees
WHERE NULL = NULL;
gives NO ROWS SELECTED.
Well, I understand that I can not compare a NULL value using operators except IS NULL and IS NOT NULL.
But why should it yield a result and not an error.
Could somebody explain me this.
Does Oracle treat NULL as a column as well as empty cells?

A where clause consists of conditional expressions. There is no requirement that a conditional expression consist of a column name on either side. In fact, although usually one or both sides are columns, it is not uncommon to have expressions that include:
subqueries
parameters
constants
scalar functions
One common instance is:
WHERE 1 = 1 AND . . .
This is a sign of automatically generated code. It is easier for some programmers to knit together conditions just by including AND <condition> but the clause needs an anchor. Hence, 1 = 1.
The way the WHERE clause works conceptually is that the clause is evaluated for each row produced by the FROM. If the clause evaluates to TRUE, then the row is kept in the result set (or for further processing). If it is FALSE or NULL, then the row is filtered out.
So, NULL IS NULL evaluates to TRUE, so all rows are kept. NULL = NULL evaluates to NULL, so no rows are kept.

NULL is NULL is always true, NULL = NULL is always false. Also, you aren't testing against any columns in either query (thus you are only going to get everything or nothing).

Related

Keep null rows after filtering [duplicate]

This question already has answers here:
SQL not displaying null values on a not equals query?
(5 answers)
Closed 20 hours ago.
Before select
Status could be:
X1, X2, NULL
SELECT * FROM surrtest t Where t.Status != „X2“
It’s deleting also rows where Status was null. But it shouldn’t.
So after query I’m only getting rows where status Is X1 but I also want the NULL rows.
Is it possible?
I don’t know if it’s possible. If not maybe there is a workaround where we replace the null values with empty strings? But I hope it is possible without changing the data.
This should work:
SELECT * FROM surrtest Where Status != ‘X2’ or Status is null
If that doesn’t work then there’s something weird going on with your database.
In most databases, a where clause evaluates to either true, false, or unknown. Any comparison with null will result in an unknown result. Since a where clause filters out all records that don't evaluate to true, you will not see records that evaluate to unknown, as well as false.
In your original query, the where clause was filtering out null records, because they evaluated to unknown. So, you have to add the extra part or Status is null to the where clause to include the null records.
Also, do NOT use or Status = null, since that will always evaluate to unknown, like mentioned before. You must use or Status is null.

Difference between "=" and "is" in sql server

I am having problem while understanding = and is operators in SQL Server.
Consider the following example queries which are having different behaviors in their respective output:
SELECT * FROM tableName WHERE colName IS NULL;
SELECT * FROM tableName WHERE colName = NULL;
First query will provide the required output i.e. select those records for which colName is having a null value. But the second query will result in zero matching records.
Please clarify different uses of these operators with pros and cons.
EDIT
Here, most of the answers are claiming that = doesn't work with null, but the following statement will work with null and =.
SET ANSI_NULLS OFF
SELECT * FROM tableName WHERE colName = NULL;
This will provide the same result as statement having is operator.
Nothing equals null.
Not even null equals null.
null is not a value, it is more like a concept, or a mark, meaning unknown value.
As such, you need two operators for this, one for equality, and one for checking the concept of null.
Once you start to think of null as "unknown value" a lot of the other behavior also makes sense.
10 + null? Add an unknown value to 10? Obviously you will have another unknown value as a result.
For more information, please check the documentation of the equality operator in T-SQL.
Additionally, see the documentation for SET ANSI_NULL.
Note that the documentation is in conflict about the behavior of x = null between the equality operator (documentation says it will always be false if x is non-null) whereas SET ANSI_NULLS documentation says that x = null will behave equivalent to x is null when the option is turned on.
From http://msdn.microsoft.com/en-us/library/ms188795.aspx:
To determine whether an expression is NULL, use IS NULL or IS NOT NULL instead of comparison operators (such as = or !=). Comparison operators return UNKNOWN when either or both arguments are NULL.
EDIT
The originating question was updated to note that SET ANSI_NULLS OFF allows:
select * from tableName where colName = null.
This may be true at the moment but future versions of SQL server will set ANSI_NULLS always ON and any calls to SET ANSI_NULLS OFF will result in an error.
Source: http://msdn.microsoft.com/en-us/library/ms188048.aspx
= NULL is always unknown (this is piece of 3 state logic), but WHERE clause treats it as false and drops from the result set. So for NULL you should use IS NULL
= NULL is used for assignment to a NULL value whereas IS NULL is used to determine whether a variable is NULL-valued.
See these articles on null
Wikipedia NUll (SQL)
w3schools SQL NULL Values
SQL Tutorial, see IS NULL Operator section
Null is not same as zero. Null is absence of value. It simply means that the value could be anything. It is unknown.
Q. Why select * from tableName where colName = null returns zero rows?
A. Because you can not be sure that one null(unknown value) is equal to or not equal to another null(another unknown value).
EG:
I have a magic hat and nobody knows what will come out of it(if anything comes out at all).
You have another magic hat and nobody knows what will come out of it(if anything comes out at all).
We both have a magic hat each and what it has inside is unknown (null).
These both hats could contain a rabbit each or may be my hat contains a hammer and your's has a pineapple.
If you have an if condition like this..
if(#flag<>null)
it is a mistake because if you pass null to #flag you do not really know whether or not #flag is equal or not equal to null
Use if(#flag<>isnull(null,'')) instead

Proc Sql case confusion

Within SAS
I have a proc-sql step that I'm using to create macro variables to do some list processing.
I have ran into a confusing step where using a case statement rather than a where statement results in the first row of the resulting data set being a null string ('')
There are no null strings contained in either field in either table.
These are two sample SQL steps with all of the macro business removed for simplicity:
create table test as
select distinct
case
when brand in (select distinct core_brand from new_tv.core_noncore_brands) then brand
end as brand1
from new_tv.new_tv2
;
create table test2 as
select distinct brand
from new_tv.new_tv2
where brand in (select distinct core_brand from new_tv.core_noncore_brands)
;
using the first piece of code the result is a table with multiple rows, the first being an empty string.
The second piece of code works as expected
Any reason for this?
So the difference is that without a WHERE clause you aren't limiting what you are selecting, IE every row is considered. The CASE statement can bucket items by criteria, but you don't lose results just because your buckets don't catch everything, hence the NULL. WHERE limits the items being returned.
Yes, the first has no then clause in the case statement. I'm surprised that it even parses. It wouldn't in many SQL dialects.
Presumably you mean:
create table test as
select distinct
case
when brand in (select distinct core_brand from new_tv.core_noncore_brands)
then brand
end as brand1
from new_tv.new_tv2
;
The reason you are getting the NULL is because the case statement is return NULL for the non-matching brands. You would need to add:
where brand1 is not NULL
to prevent this (using either a subquery or making brand1 a calculated field).
Your first query is not correct, there is no 'then' statement in the 'case' clause.
create table test as
select distinct
case
when brand in (select distinct core_brand from new_tv.core_noncore_brands)
*then value*
end as brand1
from new_tv.new_tv2
;
Probably, you have NULL value because there is no default value for the 'case' clause, so for the value which doesn't meet the condition it returns NULL. There is a difference between 'case' clause and 'NOT IN', the first returns you all the rows, but without values, which do not meet condition, when second query will return only row which meet condition.

Invalid Number Error! Can't seem to get around it

Oracle 10g DB. I have a table called s_contact. This table has a field called person_uid. This person_uid field is a varchar2 but contains valid numbers for some rows and in-valid numbers for other rows. For instance, one row might have a person_uid of '2-lkjsdf' and another might be 1234567890.
I want to return just the rows with valid numbers in person_uid. The SQL I am trying is...
select person_uid
from s_contact
where decode(trim(translate(person_uid, '1234567890', ' ')), null, 'n', 'c') = 'n'
The translate replaces all numbers with spaces so that a trim will result in null if the field only contained numbers. Then I use a decode statement to set a little code to filter on. n=number, c=char.
This seems to work when I run just a preview, but I get an 'invalid number' error when I add a filter of...
and person_uid = 100
-- or
and to_number(person_uid) = 100
I just don't understand what is happening! It should be filtering out all the records that are invalid numbers and 100 is obviously a number...
Any ideas anyone? Greatly Appreciated!
Unfortunately, the various subquery approaches that have been proposed are not guaranteed to work. Oracle is allowed to push the predicate into the subquery and then evaluate the conditions in whatever order it deems appropriate. If it happens to evaluate the PERSON_UID condition before filtering out the non-numeric rows, you'll get an error. Jonathan Gennick has an excellent article Subquery Madness that discusses this issue in quite a bit of detail.
That leaves you with a few options
1) Rework the data model. It's generally not a good idea to store numbers in anything other than a NUMBER column. In addition to causing this sort of issue, it has a tendency to screw up the optimizer's cardinality estimates which leads to less than ideal query plans.
2) Change the condition to specify a string value rather than a number. If PERSON_UID is supposed to be a string, your filter condition could be PERSON_UID = '100'. That avoids the need to perform the implicit conversion.
3) Write a custom function that does the string to number conversion and ignores any errors and use that in your code, i.e.
CREATE OR REPLACE FUNCTION my_to_number( p_arg IN VARCHAR2 )
RETURN NUMBER
IS
BEGIN
RETURN to_number( p_arg );
EXCEPTION
WHEN others THEN
RETURN NULL;
END;
and then my_to_number(PERSION_UID) = 100
4) Use a subquery that prevents the predicate from being pushed. This can be done in a few different ways. I personally prefer throwing a ROWNUM into the subquery, i.e. building on OMG Ponies' solution
WITH valid_persons AS (
SELECT TO_NUMBER(c.person_uid) 'person_uid',
ROWNUM rn
FROM S_CONTACT c
WHERE REGEXP_LIKE(c.personuid, '[[:digit:]]'))
SELECT *
FROM valid_persons vp
WHERE vp.person_uid = 100
Oracle can't push the vp.person_uid = 100 predicate into the subquery here because doing so would change the results. You could also use hints to force the subquery to be materialized or to prevent predicate pushing.
Another alternative is to combine the predicates:
where case when translate(person_uid, '1234567890', ' ')) is null
then to_number(person_uid) end = 100
When you add those numbers to the WHERE clause it's still doing those checks. You can't guarantee the ordering within the WHERE clause. So, it still tries to compare 100 to '2-lkjsdf'.
Can you use '100'?
Another option is to apply a subselect
SELECT * FROM (
select person_uid
from s_contact
where decode(trim(translate(person_uid, '1234567890', ' ')), null, 'n', 'c') = 'n'
)
WHERE TO_NUMBER(PERSON_UID) = 100
Regular expressions to the rescue!
where regexp_like (person_uid, '^[0-9]+$')
Use the first part of your query to generate a temp table. Then query the temp table based on person_uid = 100 or whatever.
The problem is that oracle tries to convert each person_uid to an int as it gets to it due to the additional and statement in your where clause. This behavior may or may not show up in the preview depending on what records where picked.

SQL: Why are NULL values filtered out within this where clause?

In my table, I have a nullable bit column (legacy system...) and another developer recently made a change to a stored procedure to only show values where the bit column was not true (1). Because this is a nullable column, we noticed that if the column was NULL, the record was not being picked up. WHY is this?
Both the other developer and I agree that NULL <> 1... Is this a bug in SQL or was this designed this way? Seems like a design flaw.
Current Code:
(VoidedIndicator <> 1)
Proposed Fix:
(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)
Clarification (By Jon Erickson)
VoidedIndicator is a nullable bit field so it can have the following values: NULL, 0, or 1
When a SQL statement is created with a where clause such as (VoidedIndicator <> 1) we only get records returned that have VoidedIndicator == 0, but we were expecting both VoidedIndicator == 0 and VoidedIndicator IS NULL. Why is this?
Lots of good answers, but let me give you a really concise version.
To SQL, Null does NOT mean "No value" it means "Unknown Value"
With that in mind, consider the answer to the question you are asking SQL in plain English.
Q: Is this unknown value not equal to 1?
A: I don't know, there is no way to tell without knowing the value.
Hence Null<>1 = Null
From the Wikipedia entry on NULL:
For example, a WHERE clause or
conditional statement might compare a
column's value with a constant. It is
often incorrectly assumed that a
missing value would be "less than" or
"not equal to" a constant if that
field contains Null, but, in fact,
such expressions return Unknown. An
example is below:
-- Rows where num is NULL will not be returned,
-- contrary to many users' expectations.
SELECT * FROM sometable WHERE num <> 1;
Basically, any comparison between NULL and something else, whether it's with = or <> will not be true.
As another reference, the MSDN T-SQL page on <> states:
Compares two expressions (a comparison
operator). When you compare nonnull
expressions, the result is TRUE if the
left operand is not equal to the right
operand; otherwise, the result is
FALSE. If either or both operands are
NULL, see SET ANSI_NULLS
(Transact-SQL).
The SET ANSI_NULLS page then states:
When SET ANSI_NULLS is ON, a SELECT
statement that uses WHERE column_name
= NULL returns zero rows even if there are null values in column_name. A
SELECT statement that uses WHERE
column_name <> NULL returns zero rows
even if there are nonnull values in
column_name.
...
When SET ANSI_NULLS is ON, all
comparisons against a null value
evaluate to UNKNOWN. When SET
ANSI_NULLS is OFF, comparisons of all
data against a null value evaluate to
TRUE if the data value is NULL.
It's not a bug.
NULL is not equal to anything, not even NULL (NULL = NULL returns FALSE).
Typically NULL values aren't indexed either. It's generally a bad idea to rely on a particular value or NULL. Depending on what you're storing in the column, you may be better off putting a dummy or sentinel value in rather than using NULL to indicate some meaning.
The other folks are correct that NULL <> 1 doesn't evaluate as true, therefore it doesn't satisfy the WHERE clause.
The proposed fix you describe is the best way of handling it:
(VoidedIndicator <> 1 OR VoidedIndicator IS NULL)
SQL-99 does have a predicate that helps in this case, called IS DISTINCT FROM:
(VoidedIndicator IS DISTINCT FROM 1)
This predicate would behave exactly the same as your proposed fix. Unfortunately, Microsoft SQL Server does not support IS DISTINCT FROM yet.
You can also: isnull(VoidedIndicator,1) <> 1
Because the WHERE clause only selects rows when the condition evaluates to true.
When one of the operands is NULL, the condition usually evaluates to UNKNOWN (approximately equivalent to NULL), and therefore is not true. It applies to both 'column = 1' and 'column <> 1'; if column is NULL, the search condition fails.
It is why you get told to avoid NULL columns whenever possible.
NULL <> 1 evaluates (theoretically) to "maybe", which means the record will not be returned.