Why do two seemingly identical where clauses involving nulls produce different results - tsql

I'm trying to select all records that don't have a null in a particular column and it's value isn't in another table.
So this particular situation I want to get all 'Instructors' from an import table that aren't already in the Individuals table. Obviously I don't want any blank instructors. My first attempt I tried using in the where clause:
(Instructor IS NOT NULL OR Instructor <> '')
However the results still included all blank records. When I tried using
ISNULL(Instructor, '') <> ''
I got the desired result. I can't see how these two where clauses could possibly produce different results. To me it seems like ISNULL converting the value to empty string for comparison should have exactly the same outcome as comparing the column to null then to empty string. What am I missing here? I'm guessing it's to do with the oddness of null values.
Below are the full queries
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (Instructor IS NOT NULL OR Instructor <> '')
SELECT * FROM [tempimporttblTrainingLog]
LEFT JOIN tblIndividual I ON [Instructor] = I.FirstName + ' ' + I.Surname
WHERE (I.FirstName + ' ' + I.Surname IS NULL) AND (ISNULL(Instructor, '') <> '')

ISNULL(Instructor, '') <> '' (1)
is equivalent to
(Instructor IS NOT NULL AND Instructor <> '') (2)
not
(Instructor IS NOT NULL OR Instructor <> '') (3)
If Instructor IS NULL, (1) and (2) will return FALSE, when (3) returns TRUE.
Same for when Instructor = ''.

ISNULL(Instructor, '') <> ''
won't return blank records, and you have an OR in the
(Instructor IS NOT NULL OR Instructor <> '')
line, meaning it will return anything which isn't null as well as non blanks, did you mean to put an AND instead?

Related

Postgres query for IN(NULL, 'test') does not work

When I wan't to match a column that has some certain string values or is null, I assumed I can do something like this:
SELECT * FROM table_name WHERE column_name IN (NULL, 'someTest', 'someOtherTest');
But it does not return the columns where column_name set set to NULL. Is this anywhere documented? Why does it not work?
You can't compare NULL values using = (which is what IN is doing).
Quote from the manual
Ordinary comparison operators yield null (signifying “unknown”), not true or false, when either input is null. For example, 7 = NULL yields null, as does 7 <> NULL
You need to add a check for NULL explicitly:
SELECT *
FROM table_name
WHERE (column_name IN ('someTest', 'someOtherTest') OR column_name IS NULL);
NULL and empty string (i.e ' ') both are considered different in Postgres, unlike Oracle.
The query can be modified as:
SELECT *
FROM table_name
WHERE (column_name IN ('someTest', 'someOtherTest', '', ' ') OR
column_name IS NULL);

PostgreSQL concatenate integer and real and add units

I want to concatenate 4 columns in a PostgreSQL query and add units if columns aren't empty.
SELECT
CASE
WHEN a.length_m notnull THEN a.length_m || 'm'
WHEN a.area_ar notnull THEN a.area_ar || 'ar'
WHEN a.vol notnull THEN a.vol || 'cbm'
WHEN a.pcs notnull THEN a.pcs || 'pcs'
END as quant;
FROM actions a;
This works fine, but if I have values in two colums it only shows me the first one.
How must I change my query, so that a second WHEN gets evaluated?
Use COALESCE:
SELECT COALESCE(a.length_m ||'m', '') ||
COALESCE(a.area_ar ||'ar', '') ||
COALESCE(a.vol ||'cbm', '') ||
COALESCE(a.pcs ||'pcs', '') as quant
FROM actions a;

How to match not null + not empty?

I have to do some queries on a messy database. Some columns are filled with either null or an empty string. I can do a query like this:
select * from a where b is not null and b <> '';
But is there a shortcut for this case? (match every "not empty" value) Something like:
select * from a where b is filled;
Just:
where b <> ''
will do what you want as null <> '' is null and the row will not be returned
select * from a where COALESCE(b, '') <> '';

Postgres: Concat multiple columns, while including nulls

I have a table with four columns that I need to concat. Two of the columns contain some NULL values.
I need the result to contain separators indicating all four columns, like so:
colA,colB,colC,colD
or if one column (here colB) was null,
colA,,colC,colD
I can't seem to find a clean way to do this. The best I have come up with is:
concat_ws(colA, COALESCE(colB, ''), COALESCE(colC, ''), colD, ',')
This feels cumbersome (especially because I need to do this repeatedly). Is there a better way?
Since the final value can't be NULL, you don't need to worry about preserving them. Just use an empty string. This is how you'd write it in standard SQL.
select coalesce(cola, '') || ', ' ||
coalesce(colb, '') || ', ' ||
coalesce(colc, '') || ', ' ||
coalesce(cold, '')
from your_table_name;
The concat_ws() function doesn't skip empty strings, but it does skip null columns. That means you still have to use coalesce().
select concat_ws(', ', coalesce(cola, ''),
coalesce(colb, ''),
coalesce(colc, ''),
coalesce(colb, ''))
from your_table_name;
I think you should use a cursor and then a loop also, in order to show null values you must use a nvl() function, like this:
PROCEDURE TODO IS
vAux in VARCHAR2;
CURSOR CUR_TEST IN
SELECT NVL(colb, 'replace_with'), colA, colD
FROM DUAL;
Begin
for x in CUR_TEST loop
vAux := x.colb||','||x.colA||','||x.colD;
end loop;
end TODO;
For checking what nvl() does: http://www.techonthenet.com/oracle/functions/nvl.php

SQL if statement to fix issue

I have this select
insert into test(t_name)
(select users.first_name || '_' || users.last_name
|| '_' || to_date($values.report_date, 'YYYY.MM.DD')
from users where users.id = $session.user_id)
which works as supposed, except I want it if users.first_name/users.last_name are null and user_id=0 to insert another string 'admin' otherwise I get error because it violates not-null constraint on column t_name.
Any suggestions are appreciated. Thanks.
Use a CASE in the SELECT part:
insert into test (t_name)
select case
when users.first_name is null and users.last_name is null and users.id=0 then 'admin'
else users.first_name || '_' || users.last_name || '_' || to_date($values.report_date,'YYYY.MM.DD')
end
from users
where users.id = $session.user_id
It's not clear (to me) from the question if all conditions you mentioned have to be true or just one of them. Depending on what you want, you should change the ANDs to ORs in the first WHEN part.
(Note that there is no need to enclose the SELECT in () for an INSERT ... SELECT statement)
If you are using MySQL you can use IFNULL.
INSERT INTO test(t_name)
(
SELECT IFNULL(users.first_name || '_' || users.last_name || '_' || to_date($values.report_date, 'YYYY.MM.DD'), 'admin')
FROM users
WHERE users.id = $session.user_id
)
In MSSQL there is a similar ISNULL function, I assume that there is likewise solutions for other database systems.