Why COALESCE, NULLIF and CAST are used? - sql

Can anyone please let me know why the following line is used in the query?
SELECT user_id
COALESCE(NULLIF(CAST(user_id AS VARCHAR(10)) ,'0'), '')
FROM users
user_id is of type int. But if I run the following, it shows the same output as above.
SELECT user_id FROM users

Let's check it out by parts:
COALESCE(NULLIF(CAST(user_id AS VARCHAR(10)) ,'0'), '')
COALESCE is a method useful when you want ensure some value instead NULL
imagine some query and a specific column will be used to a math operation, you will prefer receive 0 instead of NULL. So COALESCE(USE THIS VALUE IF IS NOT NULL, OR USE THIS)
NULLIF check two arguments, and return null in the case they have same value, otherwise return value of first argument
CAST is a method to transform the type of something into other type, such the integer 1 into string "1", remember 1 is not equal to "1"
so
COALESCE(NULLIF(CAST(user_id AS VARCHAR(10)) ,'0'), '')
means, if the converted to string value of user_id is '0', I want this to evaluate to '', otherwise return it transformed into a string value.

Strictly speaking, the answer to "why it's used" is "it doesn't have to be used", because there's a way to express it that's easier to understand and performs better.
Your observation that the output is the same is incorrect: It looks the same, but it isn't the same because user_id is an integer in the table and the simple query out, but varchar(10) in the complicated query output.
This produces equivalent output:
SELECT
CASE
WHEN user_id = 0 THEN ''
ELSE CAST(user_id AS VARCHAR(10))
END AS user_id
FROM users
And needs no explanation to understand.

Related

array_length() and cardinality() of an empty array return one of array size

I have a table like :
CREATE TABLE psdc_psr
(
id bigint not null,
available_region_code character varying(255)[],
is_valid bigint,
)
I want usearray_length(), cardinality() or available_region_code ='{}' to select empty available_region_code columns but it failed, the length return one.
Why does this happen and how to solve this problem.
I don't know what reason causes this problem. Maybe like jjanes say in the comments the array has a non-printing character.
In the last, I use (CAST(ARRAY_TO_JSON(available_region_code) AS VARCHAR) IN ('[null]', '[""]')) to check empty array which learn from answer of Zone in question(How to check if an array is empty in Postgres).
The result on blow:
for a similar issue I had in presto based SQL, I created a case statement like:
case when available_region_code[1] = '' then 0 else cardinality(available_region_code) end as cardinality
Not sure if this helps in your use case, but it resulted in 0's for my empty arrays, and the correct counts for all others.

How to query empty string in postgresql?

I have table, in which a column has empty fields.when i try to run simple query like below it is not
returning the data.
select * from table1 where "colunm1" = ''
But below two queries returns data
1,
select * from table1
where coalesce("colunm1", '') = ''
2,
select * from table1
where "colunm1" is null
Can someone tell me the reason?
TIA
You have describe the behavior of a column that is NULL. NULL is not the same as an empty string.
It fails any equality comparison. However, you can use is null or (less preferentially) coalesce().
The only database that treats an empty string like a NULL value, is Oracle.
Logically, for a DBMS, that would be wrong.
Relational DBMSs are all about :
set theory
Boolean algebra
A NULL value is a value that we don't know. A string literal of '' is a string whose value we know. It is a string with no characters, with a length of 0. We don't know of a NULL as a string how long it is, how many and, if any, which, characters it contains.
So it is only logical that:
the comparison '' = '' will evaluate to TRUE
the comparison NULL = NULL will evaluate to FALSE , as any comparison with a NULL value will evaluate to FALSE.
And functions like COALESCE() or NVL(), IFNULL(), ISNULL() will return the first parameter if it does not contain a NULL value. That is consistent.
Except in Oracle

Conversion failed when converting the varchar value 'x' to data type int

I have a WHERE condition which works for the type STRING but fails for an of type INT
isnull(emp.name, 'x') <> isnull(mst.name, 'x') -- works
But this condition below throws an error:
isnull(emp.age, 'x') <> isnull(mst.age, 'x') -- fails
Conversion failed when converting the varchar value 'x' to data type int.
where name is a STRING and age is of INT type.
How to rectify this?
Don't use isnull() for this purpose -- or even coalesce(). Just expand out the logic:
where (emp.age = mst.age or emp.age is null and mst.age is null)
You could put in a fake value and use coalesce(), but the types need to be consistent. However, I think you are better off with explicit logic that does what you want and works for all data types.
ISNULL will attempt to convert the datatype of second parameter to that of first parameter. The string x cannot be converted to int (assuming age is int). Use an integer value that, ideally, does not exist in your data:
isnull(emp.age, -1) <> isnull(mst.age, -1)
Note that in your code, 'x' will effectively be considered the same as NULL, which is unlikely to be what you want. Fixing the error you get for age will not correct that problem.
Consider instead using the operator IS DISTINCT FROM, which is similar to <> but considers NULL as a "known value" (NULL IS DISTINCT FROM NULL = FALSE for example).
emp.name IS DISTINCT FROM mst.name
emp.age IS DISTINCT FROM mst.age
If your database engine does not support IS DISTINCT FROM then this related question will be helpful: How to rewrite IS DISTINCT FROM and IS NOT DISTINCT FROM?

SQL server casting string to integer checking value before casting

I have a table with a field named MINIMUM_AGE. The values stored in this field are of type nvarchar:
17 years
54 years
N/A
65 years
I would like to apply a WHERE clause on the column to check for a certain age range. To do that I need to parse out the age from the field values.
So, I think I need to select the first two characters, then cast them into an integer. Also, some fields may not contain numbers for the first two characters. Some may simply be N/A. So, I will need to check for that before casting.
Can someone explain how to accomplish this?
Here is the SQL Fiddle that demonstrates the below query:
SELECT CASE
WHEN MINIMUM_AGE <> 'N/A'
THEN CAST(LEFT(MINIMUM_AGE, 2) AS int)
ELSE 0
END
FROM MyTable
Note: the CASE expression can only return one data type. So, in the example above if the MINIMUM_AGE is N/A then it returns 0.
If you would rather have it return null, then use the following:
SELECT CASE
WHEN MINIMUM_AGE <> 'N/A'
THEN CAST(LEFT(MINIMUM_AGE, 2) AS int)
END
FROM MyTable

Why IsNull(LTrim(RTrim(Lower(null))), -1) is *?

Today I was testing something at work place and came across this one
Case 1:
Declare #a nvarchar(20)
Set #a = null
Select IsNull(LTrim(RTrim(Lower(#a))), -1)
Case 2:
Select IsNull(LTrim(RTrim(Lower(null))), -1)
The result in case 1 is -1 but * in case 2
I was expecting same results in both cases. Any reason?
Without the declaration of data type, null in this case is declared as varchar(1). You can observe this by selecting the results into a #temp table:
Select IsNull(LTrim(RTrim(Lower(null))), -1) as x INTO #x;
EXEC tempdb..sp_help '#x';
Among the results you'll see:
Column_name Type Length
----------- ------- ------
x varchar 1
Since -1 can't fit in a varchar(1), you are getting * as output. This is similar to:
SELECT CONVERT(VARCHAR(1), -1);
If you want to collapse to a string, then I suggest enclosing the integer in single quotes so there is no confusion caused by integer <-> string conversions that aren't intended:
SELECT CONVERT(VARCHAR(1), '-1'); -- yields "-"
SELECT CONVERT(VARCHAR(30), '-1'); -- yields "-1"
I would not make any assumptions about how SQL Server will handle a "value" explicitly provided as null, especially when complex expressions make it difficult to predict which evaluation rules might trump data type precedence.
In SQL Server, there are "typed NULLs" and "untyped NULLs".
In the first case, the NULL is typed—it is aware that NULL is a varchar(20) and so as your functions wrap the inner value, that data type is propagated throughout the expression.
In the second case, the NULL is untyped, so it has to infer the NULL's type from the surrounding expressions. The IsNull function evaluates the data type of the first operand and applies that to the whole expression, and thus the NULL defaults to varchar(1):
PRINT sql_variant_property(IsNull(LTrim(NULL), -1), 'BaseType'); -- varchar
PRINT sql_variant_property(IsNull(LTrim(NULL), -1), 'MaxLength'); -- 1
Another complication is that IsNull does not do type promotion in the same way that Coalesce does (though Coalesce has its own problems due to not being a function—it is expanded to a CASE expression, sometimes causing unexpected side-effects due to repeat expression evaluation). Look:
SELECT Coalesce(LTrim(NULL), -1);
This results in -1 with data type int!
Check out Sql Server Data Type Precedence and you'll see that int is much higher than varchar, so the whole expression becomes int.
The naked NULL is being passed to LOWER(), which expects a character. This is being defaulted to one character wide. The value "-1" doesn't fit in this field, so it is returning "*".
You can get the same effect with:
select isnull(CAST(NULL as varchar(1)), -1)
The following code also causes the problem:
declare #val varchar;
set #val = -1
select #val
Note that COALESCE() does not cause this problem.
I'm pretty sure this is fully documented behavior.