Reputation: 443
I have a date column which holds either a date value or null. I use that to hold a product's expiration date. I want to write a query to fetch them in this order: Not yet expired, no expiration (null), and expired.
For example, assuming today is May 15:
prd_id prd_name Expiry Date
-----------------
1 name1 May 16
2 name2 May 17
3 name3 May 18
4 name4 May 21
5 namex null
6 namex null
7 namex null
8 namex May 14
9 namex May 12
(A null value denotes no expiration)
How would I do this?
Upvotes: 0
Views: 186
Reputation: 10094
Essentially, you'll be joining three separate queries together:
SELECT * FROM (SELECT * FROM `product_entries` WHERE expires_on IS NOT NULL AND expires_on > CURDATE()
ORDER BY expires_on ASC) a
UNION ALL
SELECT * FROM (SELECT * FROM `product_entries` WHERE expires_on IS NULL) b
UNION ALL
SELECT * FROM (SELECT * FROM `product_entries` WHERE expires_on IS NOT NULL AND expires_on <= CURDATE()
ORDER BY expires_on DESC) c
The first one returns those that haven't expired, the second returns those without expiration, and the third one returns expired entries.
Keep in mind that you'd want the expires_on
column to be indexed. Also, as you can see in the third query, I'm counting the current date as being expired. If you want the current day to count as not being expired, then change the <=
to <
in the third query, and >
to >=
in the first query.
Another alternative would to be to use a CASE clause (if you're not concerned about the order of each entry, so long as the non-expired are at the top, the perpetual products are in the middle, and the expired entries are at the bottom)
mysql> SELECT * FROM product_entries ORDER BY CASE
-> WHEN expires_on >= CURDATE() THEN 3
-> WHEN expires_on IS NULL THEN 2
-> WHEN expires_on < CURDATE() THEN 1
-> END DESC;
+----+-------------+
| id | expire_date |
+----+-------------+
| 9 | 2015-05-11 |
| 8 | 2015-05-06 |
| 7 | 2015-05-01 |
| 10 | NULL |
| 6 | 2015-04-26 |
| 5 | 2015-04-21 |
| 4 | 2015-04-16 |
| 3 | 2015-04-11 |
| 2 | 2015-04-06 |
| 1 | 2015-04-01 |
+----+-------------+
Upvotes: 1
Reputation: 13509
You can try follwing Syntax:-
SELECT *
FROM YOUR_TABLE
ORDER BY CASE WHEN expire_date > CURDATE() THEN 1 END,
WHEN expire_date IS NULL THEN 2 Desc END,
WHEN expire_date < CURDATE() THEN 3 Desc END;
Upvotes: 1