Conditional sorting in MySQL? - sql

I have "tasks" table with 3 fields:
date
priority (0,1,2)
done (0,1)
What I am trying to achieve is with the whole table sorted by done flag, tasks that are not done should be sorted by priority, while tasks that are done should be sorted by date:
Select * from tasks order by done asc
If done=0 additionally order by priority desc
If done=1 additionally order by date desc
Is it possible to do this in MySQL without unions?
Thanks.

You could try ORDER BY (done asc, aux desc) where aux is computed with a CASE to yield either priority or date based on the value of done (you may have to cast them to the same type to fit in the same expression, e.g. cast the date to a suitable integer day number).
For example:
SELECT * FROM tab
ORDER BY done desc,
case done
when 0 then prio
else to_days(thedate)
end desc;

Taken from Alex Martelli just shortened a bit with IF() and fixed the ASC/DESC ordering
SELECT * FROM tab
ORDER BY done ASC, IF(done, to_days(thedate), prio) DESC;

Related

Get first record based on time in PostgreSQL

DO we have a way to get first record considering the time.
example
get first record today, get first record yesterday, get first record day before yesterday ...
Note: I want to get all records considering the time
sample expected output should be
first_record_today,
first_record_yesterday,..
As I understand the question, the "first" record per day is the earliest one.
For that, we can use RANK and do the PARTITION BY the day only, truncating the time.
In the ORDER BY clause, we will sort by the time:
SELECT sub.yourdate FROM (
SELECT yourdate,
RANK() OVER
(PARTITION BY DATE_TRUNC('DAY',yourdate)
ORDER BY DATE_TRUNC('SECOND',yourdate)) rk
FROM yourtable
) AS sub
WHERE sub.rk = 1
ORDER BY sub.yourdate DESC;
In the main query, we will sort the data beginning with the latest date, meaning today's one, if available.
We can try out here: db<>fiddle
If this understanding of the question is incorrect, please let us know what to change by editing your question.
A note: Using a window function is not necessary according to your description. A shorter GROUP BY like shown in the other answer can produce the correct result, too and might be absolutely fine. I like the window function approach because this makes it easy to add further conditions or change conditions which might not be usable in a simple GROUP BY, therefore I chose this way.
EDIT because the question's author provided further information:
Here the query fetching also the first message:
SELECT sub.yourdate, sub.message FROM (
SELECT yourdate, message,
RANK() OVER (PARTITION BY DATE_TRUNC('DAY',yourdate)
ORDER BY DATE_TRUNC('SECOND',yourdate)) rk
FROM yourtable
) AS sub
WHERE sub.rk = 1
ORDER BY sub.yourdate DESC;
Or if only the message without the date should be selected:
SELECT sub.message FROM (
SELECT yourdate, message,
RANK() OVER (PARTITION BY DATE_TRUNC('DAY',yourdate)
ORDER BY DATE_TRUNC('SECOND',yourdate)) rk
FROM yourtable
) AS sub
WHERE sub.rk = 1
ORDER BY sub.yourdate DESC;
Updated fiddle here: db<>fiddle

SQL Query, how to order by date in specific case

I have a table 'exam_table' containing : User_ID, Exam_date, Exam_status.
Exam_status = ['Success' or 'Fail']
The question is :
Based on the above data, propose an SQL
query to finds the 5 candidates with the most failures. In case
of equality, we wish to obtain first the students whose date of first exam is the most distant in time.
I found the 5 candidates with the most failures but I still don't know how to sort them according to exam_date in case of equality.
Do you have any suggestions? Thank you in advance for helping !
Your order by is a clause which has ordering criteria separated by ,. So you can easily add another criteria, like below:
SELECT User_ID, count(exam_status) as nb_Failures
FROM exam_table
GROUP BY User_ID
ORDER BY nb_Failures, min(exam_date)
LIMIT 5;
UPDATED:
corrected by the date of the first exam:
SELECT
user_id,
MIN (exam_date) AS first_exam_date,
SUM (
CASE exam_status
WHEN 'Failed' THEN 1
ELSE 0
END
) AS nb_failures
FROM exam_table
GROUP BY user_id
ORDER BY nb_failures DESC, first_exam_date ASC
LIMIT 5;
or like this:
SELECT
user_id,
MIN (exam_date) AS first_exam_date,
COUNT(exam_status) AS nb_failures
FROM exam_table
WHERE exam_status = 'Failed'
GROUP BY user_id
ORDER BY nb_failures DESC, first_exam_date ASC
LIMIT 5;
PS: aggregate functions must also be applied to the date
PPS: but the first and second queries have different results. In the first, the date of the first exam is selected, in principle, it does not matter if it is successful or not. The second selects only the date of the first failed exam.

Get Max(date) or latest date with 2 conditions or group by or subquery

I only have basic SQL skills. I'm working in SQL in Navicat. I've looked through the threads of people who were also trying to get latest date, but not yet been able to apply it to my situation.
I am trying to get the latest date for each name, for each chemical. I think of it this way: "Within each chemical, look at data for each name, choose the most recent one."
I have tried using max(date(date)) but it needs to be nested or subqueried within chemical.
I also tried ranking by date(date) DESC, then using LIMIT 1. But I was not able to nest this within chemical either.
When I try to write it as a subquery, I keep getting an error on the ( . I've switched it up so that I am beginning the subquery a number of different ways, but the error returns near that area always.
Here is what the data looks like:
1
Here is one of my failed queries:
SELECT
WELL_NAME,
CHEMICAL,
RESULT,
APPROX_LAT,
APPROX_LONG,
DATE
FROM
data_all
ORDER BY
CHEMICAL ASC,
date( date ) DESC (
SELECT
WELL_NAME,
CHEMICAL,
APPROX_LAT,
APPROX_LONG,
DATE
FROM
data_all
WHERE
WELL_NAME = WELL_NAME
AND CHEMICAL = CHEMICAL
AND APPROX_LAT = APPROX_LAT
AND APPROX_LONG = APPROX_LONG,
LIMIT 2
)
If someone does have a response, it would be great if it is in as lay language as possible. I've only had one coding class. Thanks very much.
Maybe something like this?
SELECT WELL_NAME, CHEMICAL, MAX(DATE)
FROM data_all
GROUP BY WELL_NAME, CHEMICAL
If you want all information, then use the ANSI-standard ROW_NUMBER():
SELECT da.*
FROM (SELECT da.*
ROW_NUMBER() OVER (PARTITION BY chemical, name ORDER BY date DESC) as senum
FROM data_all da
) da
WHERE seqnum = 1;

SQL order by oldest from Unix Timestamps

How do I use SQL to order results by oldest first? I am using unix timestamps.
Thanks.
The oldest UNIX timestamp is the one that's smallest, so you want to ORDER BY my_timestamp_column ASC.
I have no idea why both the answers so far have said to order by the column DESC.
Unix time, or POSIX time, is a system for describing points in time, defined as the number of seconds elapsed since midnight proleptic Coordinated Universal Time (UTC) of January 1, 1970, not counting leap seconds
The ORDER BY clause can use ASC or DESC, if you sepcify none it will default to use ASC:
Most recent time stamps first:
SELECT * FROM tableName ORDER BY columnName DESC
Less recent time stamps first:
SELECT * FROM tableName ORDER BY columnName ASC
What's the problem you're having using ORDER BY 'unix-time-stamp-field' ASC;?
EDIT: jemfinch is right, it is ASC.
In order to get oldest first data when using unix_timetamp, run this query:
Select * FROM tablename order by FROM_UNIXTIME(ts) ASC
here:
ts respond to column of the table which has unix_timestamp.
Use ORDER BY clause with DESC modifier that reverses the results:
SELECT ... FROM ... ORDER BY timestampCol DESC;
Edit
Of course you should use ASC (or none, cause ASC is default)... ;)

Possible to use SQL to sort by date but put null dates at the back of the results set?

I have a bunch of tasks in a MySQL database, and one of the fields is "deadline date". Not every task has to have to a deadline date.
I'd like to use SQL to sort the tasks by deadline date, but put the ones without a deadline date in the back of the result set. As it is now, the null dates show up first, then the rest are sorted by deadline date earliest to latest.
Any ideas on how to do this with SQL alone? (I can do it with PHP if needed, but an SQL-only solution would be great.)
Thanks!
Here's a solution using only standard SQL, not ISNULL(). That function is not standard SQL, and may not work on other brands of RDBMS.
SELECT * FROM myTable
WHERE ...
ORDER BY CASE WHEN myDate IS NULL THEN 1 ELSE 0 END, myDate;
SELECT * FROM myTable
WHERE ...
ORDER BY ISNULL(myDate), myDate
SELECT foo, bar, due_date FROM tablename
ORDER BY CASE ISNULL(due_date, 0)
WHEN 0 THEN 1 ELSE 0 END, due_date
So you have 2 order by clauses. The first puts all non-nulls in front, then sorts by due date after that
The easiest way is using the minus operator with DESC.
SELECT * FROM request ORDER BY -date DESC
In MySQL, NULL values are considered lower in order than any non-NULL value, so sorting in ascending (ASC) order NULLs are listed first, and if descending (DESC) they are listed last.
When a - (minus) sign is added before the column name, NULL become -NULL.
Since -NULL == NULL, adding DESC make all the rows sort by date in ascending order followed by NULLs at last.