Reputation: 141
I have a query that uses union to join two sub queries e.g.
SELECT * FROM posts WHERE postTypeId=1 (e.g. blog)
UNION
SELECT * FROM posts WHERE postTypeId=2 (e.g. news)
The result set that this approach generates positions the two sub-sets sequentially ("blog" then "news").
I want to create a a result set which interleaves the two, alternating between rows from the "blog" sub-set and the "news" sub-set.
I feel that there must be a simple way to do this, but I have failed to find it.
Any suggestions would be greatly appreciated.
Nick
Upvotes: 2
Views: 1795
Reputation: 20320
Try
Set @current_row = 0
SELECT * FROM (
SELECT @current_row := @current_row + 1 as Position, posts.*
FROM posts
WHERE postTypeId=1
UNION
SELECT @current_row, posts.*
FROM posts
WHERE postTypeId=2
) dummyTableName
ORDER BY position, postTypeId
maybe
Upvotes: 2
Reputation: 141
This is solution that best works for me. It's not identical to any of the current proposals, so I have added it independently. @a, @b and @c are used to create row numbers per sub-set, meaning that in the combined results, 3 rows will share the same row number (a "row set"). This is used as the first order sort, and second order sort then orders the rows within the "row set".
SET @a = 0;
SET @b = 0;
SET @c = 0;
SELECT * FROM(
SELECT @a := @a + 1 AS sortOne, 1 AS sortTwo, posts.* FROM posts WHERE posts.postTypeId=3
UNION
SELECT @b := @b + 1 AS sortOne, 2 AS sortTwo, posts.* FROM posts WHERE posts.postTypeId=2
UNION
SELECT @c := @c + 1 AS sortOne, 3 AS sortTwo, posts.* FROM posts WHERE posts.postTypeId=1
) AS result ORDER BY sortOne, sortTwo
This solutions is derived/inspired by submitted solutions, but I don't think it appropriate to mark any of them as being an accepted solution in itself. So, credit where it's due to Thomas Clayson, Tony Hopkinson and rmunoz whose answers I've voted up. Cheers!
Upvotes: 4
Reputation: 6107
That's easy, you can add a parameter in your subquery, the parameter "rank", this way:
SET @rank=0;
SELECT @rank:=@rank+2 AS rank FROM posts WHERE postTypeId=1 (e.g. blog)
Then, you get:
0, ...
2, ...
If you do the same in the other query but init initializating rank to 1, you will get:
1, ...
3, ...
Finally "ORDER BY rank" and you will get posts and news mixed.
Upvotes: 2
Reputation: 29935
Well, here is a novel way I can think of (not tested, but you'll get the gist):
SELECT * FROM (
SELECT 1 AS query, @n := @n + 1 AS rowNumber, posts.* FROM (select @n:=0), posts WHERE posts.postTypeId=1
UNION
SELECT 2 AS query, @n := @n + 1 AS rowNumber, posts.* FROM (select @n:=0), posts WHERE posts.postTypeId=2
) ORDER BY rowNumber, query;
So this will do the two queries and then order by first rowNumber
and then by query
. What you'll end up with is something like:
rowNumber | query
1 | 1
1 | 2
2 | 1
2 | 2
etc...
SELECT @n=:0
resets the global variable n
to 0 for the query and then the @n := @n + 1
increments the value for each row.
If you need any more explanation let me know. I hope this works! :)
Upvotes: 2