Imagine that you have 2 tables like this:
mysql> SELECT * FROM theme;
+----+---------+------------+
| id | name | sort_order |
+----+---------+------------+
| 1 | Theme 1 | 1 |
| 2 | Theme 2 | 2 |
| 3 | Theme 3 | 3 |
| 4 | Theme 4 | 4 |
| 5 | Theme 5 | 5 |
| 6 | Theme 6 | 6 |
| 7 | Theme 7 | 7 |
+----+---------+------------+
mysql> SELECT * FROM article;
+----+------------+---------------------+----------+
| id | title | update_date | theme_id |
+----+------------+---------------------+----------+
| 1 | Article 1 | 2012-06-29 15:29:50 | 6 |
| 2 | Article 2 | 2012-07-18 00:00:00 | 2 |
| 3 | Article 3 | 2012-07-19 00:00:00 | 4 |
| 4 | Article 4 | 2012-07-18 00:00:00 | 4 |
| 5 | Article 5 | 2012-07-18 00:00:00 | 1 |
| 6 | Article 6 | 2012-06-26 10:30:51 | 6 |
| 7 | Article 7 | 2012-07-18 15:17:08 | 6 |
| 8 | Article 8 | 2012-06-18 00:00:00 | 4 |
| 9 | Article 9 | 2012-07-18 15:48:28 | 1 |
| 10 | Article 10 | 2012-07-09 00:00:00 | 4 |
+----+------------+---------------------+----------+
Each article is bound to one-and-only-one theme.
You want to be able to execute a query that gives you a list of article ordered like this:
sort_ordersort_ordersort_orderFor the current data, it should give the following:
+----+------------+---------------------+----------+
| id | title | update_date | theme_id |
+----+------------+---------------------+----------+
| 9 | Article 9 | 2012-07-18 15:48:28 | 1 |
| 2 | Article 2 | 2012-07-18 00:00:00 | 2 |
| 3 | Article 3 | 2012-07-19 00:00:00 | 4 |
| 7 | Article 7 | 2012-07-18 15:17:08 | 6 |
| 5 | Article 5 | 2012-07-18 00:00:00 | 1 |
| 4 | Article 4 | 2012-07-18 00:00:00 | 4 |
| 1 | Article 1 | 2012-06-29 15:29:50 | 6 |
| 10 | Article 10 | 2012-07-09 00:00:00 | 4 |
| 6 | Article 6 | 2012-06-26 10:30:51 | 6 |
| 8 | Article 8 | 2012-06-18 00:00:00 | 4 |
+----+------------+---------------------+----------+
I'm almost sure there is a way to do this using a single query but I can't figure it out.
How would you achieve this ?
This is related to the problem of partitioned ranking in MySQL. There are no windowed ranking functions in MySQL, but the generic problem can successfully be solved with the help of variables:
SELECT
id,
title,
update_date,
theme_id
FROM (
SELECT
*,
@rnk := @rnk * (@last_theme = theme_id) + 1 AS rnk,
@last_theme := theme_id
FROM article, (SELECT @rnk := 0, @last_theme := 0) s
ORDER BY theme_id, update_date DESC
) s
ORDER BY
rnk, theme_id
;
The above query both ranks the rows and then uses the rankings to sort the final result set. The query first retrieves rows from article ordering them by theme_id and update_date DESC to assign ranking numbers. Then, when selecting from the ranked row set, another, final, ordering is introduced, this time by the rankings and theme_id.
You can try this query at SQL Fiddle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With