Why does this SQL order null values last? - sql

This will apparently put null values for myDate at the bottom of the result set. What's the logic behind how this is being executed?
SELECT * FROM myTable
WHERE ...
ORDER BY CASE WHEN myDate IS NULL THEN 1 ELSE 0 END, myDate;

This is your order by:
ORDER BY (CASE WHEN myDate IS NULL THEN 1 ELSE 0 END),
myDate
The first expression for the order by says "Give the NULL values a value of 1 (for the sort) and non-NULL values a value of 0". Well, you are sorting in ascending order, so the NULL values go last.
If you want them first, use desc:
ORDER BY (CASE WHEN myDate IS NULL THEN 1 ELSE 0 END) DESC,
myDate

ORDER BY CASE WHEN myDate IS NULL THEN 1 ELSE 0 END, myDate;
When myDate is null the expression will return 1. Otherwise it will return 0. 1 is greater than 0, so when ordering by the result of that expression in ascending order (the default), null values are moved to the end.

Related

What happens when I pass an CASE expression to the LAST_VALUE function

My LAST_VALUE function looks somethin like this
LAST_VALUE(
CASE
WHEN statement_1 then 0
WHEN statement_2 then 1
WHEN statement_3 then 0
ELSE NULL
END IGNORE NULLS) OVER (PARTITION BY column1 ORDER BY column2)
Can someone explains what value is the LAST_VALUE supposed to return if there is expression.
I understand what happens when a column is passed, but incase of such expressions no clue whatsoever.
You can find the description and examples at https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions085.htm#SQLRF00655
Regards...
Btw. the CASE ... END structure is just as you are selecting values from the table field but with If condition. It doesn't affect the LAST_VALUE function.
It is something like this:
CASE WHEN ID = 1 THEN 10 WHEN ID = 2 THEN 20 ELSE 99 END
where ID = 1 is Statement1, ID = 2 is Statement2 ... and so on..
The same as if your case expression were itself a column...
SELECT
*,
LAST_VALUE(new_column IGNORE NULLS)
OVER (PARTITION BY column1
ORDER BY column2
)
FROM
(
SELECT
*,
CASE
WHEN statement_1 then 0
WHEN statement_2 then 1
WHEN statement_3 then 0
ELSE NULL
END
AS new_column
FROM
your_table
)
sub_query

PGSQL: SORT isnt executed with rollup having only one result

I'm having this code:
SELECT "monat",
CASE
WHEN count("erstkontakt_reaktionsdauer") < 3
THEN null
ELSE round(round(count("erstkontakt_reaktionsdauer"),2) / nullif(count("erstkontakt_reaktionsdauer"),0), 4)
END,
count("erstkontakt_reaktionsdauer")
FROM "schema"."tablename"
WHERE "monat" IN ('2021-04-01')
AND "monat" IS NOT NULL
GROUP BY rollup(1 )
HAVING count(*) >= 1
ORDER BY 1 NULLS FIRST
While this worked all along, When I have more than one month in
WHERE "monat" IN ('2021-04-01')
When I have only one inside the WHERE, the ROLLUP NULL isnt coming first
Using a temporary table works
SELECT * FROM (
SELECT "monat", CASE WHEN count("erstkontakt_reaktionsdauer") < 3 THEN null ELSE round(round(count("erstkontakt_reaktionsdauer"),2) / nullif(count("erstkontakt_reaktionsdauer"),0), 4) END, count("erstkontakt_reaktionsdauer") FROM "schema"."table" WHERE "monat" IN ('2021-03-01') AND "monat" IS NOT NULL GROUP BY rollup(1 ) HAVING count(*) >= 1
) t ORDER BY 1 NULLS FIRST
The Problem is, when there is only one result of the query (Rollup isnt counted), the SORT method isnt called. Using a temporary table solves this.

Random sorting with ORDER BY with CASE clause

I am testing ORDER BY clause with CASE, and came across this problem.
My test select statement:
SELECT to_date as "One", field1 as "Two"
FROM(
SELECT to_date('yyyy-mm-dd', '2017-10-10'), '333' union all
SELECT to_date('yyyy-mm-dd', '2017-09-09'), '111' union all
SELECT to_date('yyyy-mm-dd', '2017-09-09'), '222' union all
SELECT to_date('yyyy-mm-dd', '2017-09-09'), '' union all
SELECT to_date('yyyy-mm-dd', '2017-09-09'), ''
)
ORDER BY One DESC,
CASE when Two = '' then 1
else 0 end DESC
And it's result may vary in a way, that sorting by second column is random:
How should I modify CASE clause to avoid it?
In Oracle, an empty string '' is the identical to NULL so your query is:
ORDER BY
One DESC,
CASE when Two = NULL then 1 else 0 end DESC
When comparing values, the are possible states are:
Equality Result
------------------------ ------
value = value TRUE
value = other_value FALSE
value = NULL NULL
NULL = NULL NULL
Your CASE expression will only evaluate to 1 when the equality evaluates to TRUE and this will never be the result when at least one side of the equality is NULL.
What you want is to use IS NULL rather than = '':
ORDER BY
One DESC,
CASE WHEN Two IS NULL THEN 1 ELSE 0 END DESC,
Two DESC;
Which you can simplify to:
ORDER BY
One DESC,
Two DESC NULLS FIRST;
The default for DESC ordering is NULLS FIRST so you could further simplify it to:
ORDER BY
One DESC,
Two DESC;
However, I would not take it this far as you are better explicitly stating that you are expecting NULL values to be ordered before non-NULL so future developers know that that is your intended ordering (rather than just an unintentional side-effect of your query).
Add the column two as third order condition
ORDER BY One DESC,
CASE when Two = '' then 1 else 0 end DESC,
Two DESC
The second order condition only puts empty entries first and not more.

SQL Server Sorting Int Column bug

I have this SQL statement that sorts the rows depending on their change_order and change_id.
My statement looks like this:
select *
from change_dtl_from2
where chnfr_hdrno = 'CH000009'
order by
case
when chnorder is null
then 1
else 0
end asc, change_id asc
Where chnfr_hdrno is the document number, chnorder is change_order, change_id is unique key per row.
If I execute that statement, the result will be like this:
As you can see, the row with chnorder value of 5 is on the top most where the chnorder is set its order by ascending. I don't know where or what I'm doing wrong.
The default value of chnorder is null and is an int column. That's why I'm confused because whenever I add a new row, the new one will be on top most. I hope you can all help me. :)
SQL does everything correct depending on your query. With your CASE-Statement you "replace" all non-NULL-values to 1 and sort them only by change_id. If you only want to replace NULL by 1 you should use
order by (case when chnorder is null then 1 else chnordner end) asc
or you should use
order by (case when chnorder is null then 1 else 0 end) asc, chnordner asc, change_id asc

How to check if all rows validate a predicate

I've a table in my database for which I need to check if all rows have one field not null.
If there are no row or if there is at least 1 row with the field null => true
If there are rows and they are all with the field not null => False
Is there a way to do this in on simple query? Or I need to check if my table is empty first then if it's not check if I've a row with the field value empty ?
This will count how many NULL values you have in a field;
SELECT
SUM(CASE WHEN FieldName IS NULL THEN 1 ELSE 0 END) NullValues
FROM TableName
Will return 0 if there are no NULL values, and will return the number of NULLS if there are any present.
If you actually want to return a value as 'True' or 'False' then do this;
SELECT CASE
WHEN a.NullValues > 0
THEN 'True'
ELSE 'False'
END CheckField
FROM (
SELECT
SUM(CASE WHEN FieldName IS NULL
THEN 1
ELSE 0
END) NullValues
FROM TableName
) a
Use count(*) and count(field) and compare the two:
select
case when count(*) > 0 and count(*) = count(field) then 1 -- not empty and no nulls
else 0 end as isgood
from mytable;
Oracle SQL has no boolean data type , so I use 1 for true and 0 for false. You can replace this with whatever you like (e.g. 'true' instead of 1 and 'false' instead of 0).
As to turning this into a predicate (correlated to a main query), you'd use something along the lines of:
select ...
from main
where exists
(
select 1
from mytable
where mytable.colx = main.coly
having count(*) > 0 and count(*) = count(field)
);
You can do this with aggregation. However, it is difficult to understand what you are asking for. If you want to check that a field has no NULL values, you can do:
select (case when count(*) > 0 then 1 else 0 end) as HasNullValues
from t
where field is null;
Alternate way I found using max with putting null first:
select case when
max(field) keep (dense_rank first order by datfin desc nulls first) is null then 1
else 0 end as flag
from MYTABLE;