Postgres is it necessary to include two predicates in this where clause? - postgresql

I would like to write a query which returns all rows where action1 is not 't' (including instances where action1 is null)
This query does not return the null records:
select *
from actions
where action1 <> 't'
This query does return the null records, but I'm surprised both predicates are necessary
select *
from event_actions
where action_c2 is null or action_c2 <> 't'
Is there a way to write this query without both predicates?

You can use the IS DISTINCT FROM construction in the comparison, which treats null as if it is a known value that is different from any non-null value i.e.
select *
from actions
where action1 is distinct from 't'
a is distinct from b is equivalent to
case
when a is null then b is null
else a is not null then b is not null and a = b
end
For reference: https://wiki.postgresql.org/wiki/Is_distinct_from

Related

Postgres ignoring null values when using filter as not in array

SELECT * FROM Entity e WHERE e.Status <> ANY(ARRAY[1,2,3]);
Here Status is a nullable integer column. Using the above query i am unable to fetch the records whose status value is NULL.
SELECT * FROM Entity e WHERE (e.Status is NULL OR e.Status = 4);
This query does the trick. Could someone explain me why the first query was not working as expected.
NULL kinda means "unknown", so the expressions
NULL = NULL
and
NULL != NULL
are neither true nor false, they're NULL. Because it is not known whether an "unknown" value is equal or unequal to another "unknown" value.
Since <> ANY uses an equality test, if the value searched in the array is NULL, then the result will be NULL.
So your second query is correct.
It is spelled out in the docs Array ANY:
If the array expression yields a null array, the result of ANY will be null. If the left-hand expression yields null, the result of ANY is ordinarily null (though a non-strict comparison operator could possibly yield a different result). Also, if the right-hand array contains any null elements and no true comparison result is obtained, the result of ANY will be null, not false (again, assuming a strict comparison operator). This is in accordance with SQL's normal rules for Boolean combinations of null values.
FYI:
e.Status is NULL OR e.Status = 4
can be shortened to:
e_status IS NOT DISTINCT FROM 4
per Comparison operators.

number equality to null using case when

In my Postgres database, I'm checking user answers for correctness by checking if two IDs, "user_answered_id" and "expected_answer_id", are equivalent. If the user doesn't provide a "user_answered_id", then we still mark their answer as incorrect.
In Postgres, the following queries
select case when 1 != null then TRUE else FALSE end as test;
select case when 1 = null then TRUE else FALSE end as test;
both result in FALSE. This is true for any number check (e.g., when 2 != null, when 3 != null, ..., etc.
Why doesn't CASE WHEN show TRUE for 1 != null?
Must I put in the check "or is null"? E.g.,
CASE WHEN
user_answered_id != expected_answer_id
OR user_answered_id IS NULL
THEN TRUE
ELSE FALSE
END as user_incorrect_tally
What you are looking for is: IS DISTINCT FROM
select 2 is distinct from null;
?column?
----------
t
select 2 is distinct from 1;
?column?
----------
t
From the docs:
datatype IS DISTINCT FROM datatype → boolean
Not equal, treating null as a comparable value.
1 IS DISTINCT FROM NULL → t (rather than NULL)
NULL IS DISTINCT FROM NULL → f (rather than NULL)
SQL uses three-valued logic: true, false, and null. Null is not false. Null can be thought of as "no value".
Operations on null almost always yield null. So 1 != null is null. 1 = null is null. null = null is null. 5 < null is null. Etc.
To check for null, use is null and is not null.
Back to your query. is not distinct from and is distinct from are like = and != which treat null as a comparable value. So null is distinct from 1 will be true.
select
user_answered_id is distinct from expected_answer_id as user_incorrect
If you need to convert a null into a different value such as 0 or an empty string, use coalesce.
select
coalesce(user_answered_text, 'No Answer')
Your column is named "tally", but a tally means a count. If you intend to count a user's true and false answers use count with a filter.
select
count(user_answered_id) filter (
where user_answered_id = expected_answer_id
) as user_correct_tally,
-- count ignores null, this will only be the questions they tried to answer
count(user_answered_id) as user_answered_tally,
count(user_answered_id) filter (
where user_answered_is is distinct from expected_answer_id
) as user_incorrect_tally
Yes, You should check NULL value with is null, And last query you wrote is correct.
I suggest you to read below documents:
https://www.postgresql.org/docs/current/functions-comparison.html

JPQL query with input parameter collection containing null

I need to compare a nullable entity property via IN expression within the following JPQL query:
#NamedQuery(name = "query",
query = "SELECT e FROM MyEntity e WHERE e.status IN :statuses")
Now, I like the shown collection-valued input parameter statuses to optionally contain null as an element:
final List<MyEntity> actual = entityManager.createNamedQuery("query", MyEntity.class)
.setParameter("statuses", Arrays.asList(null, 1L))
.getResultList();
However with Hibernate/Derby an actual result list only contains entities with status 1L but not null.
I have not found anything in the JPA 2.2 specification about this case. Did I miss something or is this vendor-specific?
The answers to this question only solve part of my problem. In their proposed solutions, the null comparison is hard-baked into the query and cannot be controlled via the collection-valued parameter.
As a Java programmer, where null = null yields true it might come as a surprise that in SQL (and JPQL) null = null is itself null which is "falsy". As a result, null in (null) yields null as well.
Instead you need to treat null seperately with a IS NULL check: e.status IS NULL OR e.status IN :statuses.
This is described in 4.11 Null Values of the JPA Specification:
Comparison or arithmetic operations with a NULL value always yield an unknown value.
Two NULL values are not considered to be equal, the comparison yields an unknown value.

Py-postgresql: WHERE param = None not working

I am using python3.6 and py-postgresql==1.2.1.
I have the following statement:
db.prepapre("SELECT * FROM seasons WHERE user_id=$1 AND season_id=$2 LIMIT 1), where season_id can be NULL.
I want to be able to be able to get the latest record with a NULL season_id by passing None as the $2 param, but it does not work. Instead, I need to create this second statement:
db.prepapre("SELECT * FROM seasons WHERE user_id=$1 AND season_id IS NULL LIMIT 1)
It must have something to do with season_id = NULL not working and season_id IS NULL is, but is there a way to make this work?
From Comparison Functions and Operators:
Do not write expression = NULL because NULL is not “equal to” NULL. (The null value represents an unknown value, and it is not known whether two unknown values are equal.)
Some applications might expect that expression = NULL returns true if expression evaluates to the null value. It is highly recommended that these applications be modified to comply with the SQL standard. However, if that cannot be done the transform_null_equals configuration variable is available. If it is enabled, PostgreSQL will convert x = NULL clauses to x IS NULL.
and:
19.13.2. Platform and Client Compatibility
transform_null_equals (boolean)
When on, expressions of the form expr = NULL (or NULL = expr) are treated as expr IS NULL, that is, they return true if expr evaluates to the null value, and false otherwise. The correct SQL-spec-compliant behavior of expr = NULL is to always return null (unknown). Therefore this parameter defaults to off.
You could rewrite your query:
SELECT *
FROM seasons
WHERE user_id = $1
AND (season_id = $2 OR ($2 IS NULL AND season_id IS NULL))
-- ORDER BY ... --LIMIT without sorting could be dangerous
-- you should explicitly specify sorting
LIMIT 1;

Filtering stored procedure records by nested select case statement

I need to further refine my stored proc resultset from this post, I need to filter my resultset to display only records where emailaddr is NULL (meaning display only records that have Invoice_DeliveryType value of 'N' ).
Among numerous queries, I have tried:
select
Invoice_ID, 'Unknown' as Invoice_Status,
case when Invoice_Printed is null then '' else 'Y' end as Invoice_Printed,
case when Invoice_DeliveryDate is null then '' else 'Y' end as Invoice_Delivered,
(case when Invoice_DeliveryType <> 'USPS' then ''
when exists (Select 1
from dbo.Client c
Where c.Client_ID = SUBSTRING(i.Invoice_ID, 1, 6) and
c.emailaddr is not null
)
then 'Y'
else 'N'
end)
Invoice_ContactLName + ', ' + Invoice_ContactFName as ContactName,
from
dbo.Invoice
left outer join
dbo.fnInvoiceCurrentStatus() on Invoice_ID = CUST_InvoiceID
where
CUST_StatusID = 7
AND Invoice_ID = dbo.Client.Client_ID
AND dbo.client.emailaddr is NULL
order by
Inv_Created
but I get an error
The conversion of the nvarchar value '20111028995999' overflowed an int column
How can I get the stored procedure to only return records with DeliveryType = 'N' ?
Trying selecting the stored proc results into a temp table, then select
* from #TempTable
We could really do with a schema definition to get this problem resolved.
It appears that there is an implicit conversion occurring within one of your case statements, but without the schema def's it's difficult to track down which one.
You can't safely mix datatypes in CASE expressions, unless you are absolutely sure that any implicit conversions will work out OK you should make the conversions explicit.
Judging by the error message seeming to include something that could be a date represented as a string(20111028) plus some kind of other data ?time?(995999) it may be something to do with Invoice_DeliveryDate, but this is a shot in the dark without more details.