I have a table with about a hundred rows. It has a column is_gallery that contains either 1, 0, or NULL. If I do...
SELECT * WHERE is_gallery != 1
or
SELECT * WHERE NOT (is_gallery = 1)
it excludes the rows where is_gallery is null. I can manage to get a proper response if I do
SELECT * WHERE (is_gallery = 0 OR is_gallery is null)
But shouldn't the "!=" or NOT work? Isn't there a way to just return the rows where is_gallery doesn't equal 1 without testing for every other possibility?
You can use the IS and IS NOT operators instead of = and !=. These treat NULL like a normal value.
SELECT * FROM yourTable WHERE is_gallery IS NOT 1
The best thing to use is coalesce as in:
SELECT *
WHERE coalesce(is_gallery,0) != 1;
what coalesce does, is replaces any null value in that column with the second parameter. In the example above, any nulls in the "is_gallery" column will be replaced with 0 before it is compared with 1. So will of course return true.
On NULL realize that a NULL value isn't equal to ANYTHING - not even NULL itself. It cannot be compared - so when "comparing", it always will return FALSE. On NULL, it has a special operator which is "IS NULL" or "IS NOT NULL"
Related
I was practicing SQL with PostgreSQL and I got stuck using COALESCE, maybe someone can tell me where I am going wrong.
I have a table with four columns: title, height_cm, length_cm, and width_cm. I want to multiply three last ones and get the column "size". The problem is that the whole dataset has many NULL values and 0s which I would like to skip and return the biggest value possible with the three columns (i.e. if only height has value, return that value, if the three columns have values multiply the three). If no column has a value return "NO VALUE FOUND".
I was not able to manage "skipping" the Null values (I haven't really started with the 0s yet since I am stuck in the beginning). I thought that this would have done the trick but it did not work.
SELECT title, height_cm, length_cm, width_cm,
COALESCE(
height_cm * length_cm * width_cm,
length_cm * width_cm,
height_cm * length_cm,
height_cm * width_cm,
height_cm,
length_cm,
width_cm, 'NO VALUE FOUND') AS size
FROM artworks
ORDER BY size ASC
LIMIT 10
First of all, the system does not recognize "NO VALUE FOUND" (but when I add a 0 instead, it recognizes it), secondly, when I take the text out, the system still considers the NULL values. I am able to make it work adding
WHERE height_cm IS NOT NULL AND length_cm IS NOT NULL AND width_cm IS NOT NULL
But I thought that the main idea of COALESCE was to be able to skip the NULL values. Any suggestions?
Regarding the 0s, if I add:
WHERE height_cm != 0 AND length_cm != 0 AND width_cm != 0
I lose the rows that have values but which also have one 0.
Thanks!
EDIT with the solution from the answers
In the end I used a CTE in combination with the answers from the people who helped below, this is the final query:
WITH query AS (SELECT title, height_cm, length_cm, width_cm,
(CASE WHEN height_cm IS NULL AND length_cm IS NULL AND width_cm IS NULL
THEN 0
ELSE (COALESCE(height_cm, 1) * COALESCE(length_cm, 1) * COALESCE(width_cm, 1))
END) AS size
FROM artworks)
SELECT *
FROM query
WHERE size > 0
ORDER BY size ASC
LIMIT 10
The datatypes of all elements passed to coalesce should be the same, but I would apply coalesce to each column separately and use the default value of 1 if it's null:
coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1) as size
which is logically the same as what you've coded.
You'll need a special check in case they are all null, for which you may (ab)use coalesce too:
case
when coalesce(height_cm, length_cm, width_cm) is null then null -- or 0
else coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1)
end as size
You'll have to pick either null or some special value (eg 0) when they are all null. You may render it as "NO VALUE FOUND" to the user as you wish.
"NO VALUE FOUND" is a string type on the other hand 0 is numeric that's why when you are using 0 it does not create problem because in case of 0 all the data for this column is numeric data type but when you are trying to use string it has been created issue of mixing two different data types which will not be allowed by sql engine
I agree with Bohemian on the use of a single expression. However, I think the final expression you want returns a string:
(case when height_cm is null and length_cm is null and width_cm is null
then 'NO VALUE FOUND'
else (coalesce(height_cm, 1) * coalesce(length_cm, 1) * coalesce(width_cm, 1))::text
end) as size
Or, just live with a NULL value meaning that the value is not available.
It sounds like the function you actually want to use here is GREATEST:
SELECT
title,
height_cm,
length_cm,
width_cm,
COALESCE(
GREATEST(
height_cm * length_cm * width_cm,
length_cm * width_cm,
height_cm * length_cm,
height_cm * width_cm,
height_cm,
length_cm,
width_cm)::text, 'NO VALUE FOUND') AS size
FROM artworks
ORDER BY size
LIMIT 10;
The GREATEST function will automatically pick up on the largest non NULL value already. So, you only need COALESCE here as a catch-all for the case where the height, length, and width, all happen to be NULL at the same time.
i get confused in learning coalesce, I am new to sql.
example :
select case when value is null then 1
else value end as value
from table
and
select coalesce(value, 1)
from table
and in the tutorial I see in internet there are like
select coalesce (arg_1, arg_2, arg_3)
if I make
select coalesce(value, 1, 2)
how I can make to show the return value is 2?
Your query with the first and second will reproduce the same result, But you are wrong understanding the Coalesce concept.
Definition in Documentation Postgresql
The COALESCE function returns the first of its arguments that is not
null. Null is returned only if all arguments are null.
So it means it will return the first argument that is not null, it is not like case statement with condition like true or false
Let's try with example :
select coalesce(null, 1)
It will return 1 like the query you show, or
select coalesce(null, null, 1)
It will return 1 too even 1 in the arg_3 and how about there are 2 value not null?
select coalesce(null, 1, 2)
It will return 1. Why? Like in the documentation said "returns the first of its arguments that is not null" so when there is 2 value not null the first argument have not null value will get return
You can check this demo and try :
Demo<>Fiddle
Hope it helps
I am using Postgres and have the following SQL statement:
SELECT *
FROM "osmlocal-dsd-de".t_osm_vehicle_image t
WHERE t.vehicle_config_id = 3
and image_type_id = 2
Which returns one row:
id vehicle_config_id cosy_url image_type_id
113 3 SomeValue 2
When I run the following:
SELECT * from "osmlocal-dsd-de".t_osm_vehicle_image t
WHERE t.vehicle_config_id = 3
and image_type_id = 2
and coalesce(t.cosy_url, '') = ''
Zero rows are returned.
I think my understanding of coalesce is wrong, because I would have expected one row still to be returned, because the cosy_url is not null.
Any advise on what I am doing wrong would be appreciated.
Your understanding of coalesce is wrong
It returns the first argument that is not null. If all arguments are null, the COALESCE function will return null
In your case t.cosy_url is not null it is equally SomeValue and your condition doesn't work because SomeValue is not equal ''
You seem to be misunderstanding coalesce(). It returns the first value that is not null.
In your case, you have:
coalesce(t.cosy_url, '')
Because t.cosy_url has a value ('SomeValue'), this evaluates to that value. The value is not '' so the expression returns false and the entire where clause returns false.
If you want non-NULL values, then use:
t.cosy_url is not null
I'm querying an Oracle db for my MVC project and I found something in my SQL that I was curious about. Why does this Query not return rows where the VALIDATED_BY Column is NULL?
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
AND VALIDATED_BY <> 'AUTOUSER'
When I commented out the last line I got my expected 481 results:
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
--AND VALIDATED_BY <> 'AUTOUSER'
Finally I found I could circumvent this issue via explicitly handling the NULLs. Was this the right thing to do or was there a better way, and why?
SELECT *
FROM DM_SSA_DEV.REQUESTS
WHERE BATCH_ID = 1399
AND (VALIDATED_BY <> 'AUTOUSER' OR VALIDATED_BY IS NULL)
P.S. I'm also really using Linq in my project so this is the code I used. Most efficient?
db.REQUESTS.Where(r => r.BATCH_ID == batchId && (r.VALIDATED_BY != "AUTOUSER" || r.VALIDATED_BY == NULL)).ToList<REQUEST>();
NULL is never equal (=) to any other value, even another NULL (it is a bit like floating-point NaN). This also includes not equal expressions involving NULL.
The intent can be expressed as x = y OR (y IS NULL and x IS NULL), when NULL values are to be considered equal.
The special case of not-equal or NULL-and-not-equal is x <> y OR x IS NULL, assuming y is never NULL.
Another option is to coalesce, COALESCE(x, '*') = COALESCE(y, '*'), depending on how much the optimizer is trusted and the equality of the coalesced value to NULL. There may also be other vendor extensions.
LINQ/EF will translate x == null (C#, null must be a constant expression) to x IS NULL (SQL).
I am having trouble with some sql. When I run the following query:
Select * from teleapp;
I get TONS of results. Resulst which include a column (called cashwithappyn) that has TONS of empty or null data cells. (They look empty and don't say null)
The column info is:
ColumnName ID Null? Data Type Histogram Num Distinct Num Nulls Density
CASHWITHAPPYN 54 Y VARCHAR2(1 Byte) Frequency 2 56895 0
When I try to run the following query:
Select * from teleapp where cashwithappyn = null;
or
Select * from teleapp where cashwithappyn = '';
or
Select * from teleapp where cashwithappyn not like '';
or
Select * from teleapp where cashwithappyn not in ('Y','N');
or ANY type of combination, I cannot seem to get all of the rows with nothing in cashwithappyn.
Any ideas? Please help, this is the last part of a project that I was assigned to do and I just need to figure this out.
Thanks.
Maybe the column contains blanks. In that case you can do
WHERE TRIM(CASHWITHAPYYN) IS NULL
TRIM removes all blanks before and after and if nothing is left anymore the value becomes NULL
e.g.
TRIM(' ') IS NULL -- one blank removed = true
TRIM(NULL) IS NULL -- true
Also NULL cannot be compared with = NULL but must be phrased IS NULL. NULL is not a value as such and that is why the comparison never works.
You need to use IS NULL
Select * from teleapp where cashwithappyn is null;
Logical test expressions (=, Not In, Like etc) with null result in a false so all of the following result in false
1 = NULL
1 <> NULL
NULL = NULL
NULL <> NULL
NULL NOT IN ('a','b')
NULL Not Like NULL
Additionally in oracle the zero length string is null so NOT LIKE '' will never return any rows
You'll need to use either is null, is not null or Coalesce
A co-worker and I did a bunch of research, here's what we came up with that will work. Any ideas why this works but not the others?
Select * from teleapp where nvl(cashwithappyn,'U') = 'U';