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
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!
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! :)
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.
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
Related
I have really different problem about database query. There is a little bit different scenarios:
I have a table created with 3 columns. They have ID, ItemId, TypeId columns. I need a count query, it should count ItemId and TypeId together but except duplicate columns. For example;
Id ItemId TypeId
-- ------ ------
1 1 1 -> count +1
2 1 1 -> ignore
3 1 2 -> count -1
4 1 2 -> ignore
5 1 1 -> count +1
result count = 1
In the end, if distinct row repeated, count ignore that row. But TypeId data changed for one specific Item it should increase or decrease count. TypeId equals to 1 count +=1, equals to 2 count -=1.
In MySQL, you would seemingly use count(distinct):
select count(distinct itemId, typeId)
from t;
However, you really have a gaps-and-islands problem. You are looking at the ordering to see where things change.
If I trust that the id has no gaps, you can do:
select count(*)
from t left join
t tprev
on t.id = tprev.id + 1
where not ((t.itemId, t.typeid) <=> (tprev.itemId, t.prev.id))
Try the following query. This employs User-defined session variables. It will work in all the cases (including gaps in Id):
SELECT
SUM(dt.factor) AS total_count
FROM
( SELECT
#factor := IF(#item = ItemId AND
#type = TypeId,
0,
IF(TypeID = 2, -1, 1)
) AS factor,
#item := ItemId,
#type := TypeId
FROM your_table
CROSS JOIN (SELECT #item := 0,
#type := 0,
#factor := 0) AS user_init_vars
ORDER BY Id
) AS dt
DB Fiddle DEMO
I have a query like this:
(select #number:=3)
union
(select #number:=2)
union
(select #number:=1)
order by #number ASC
With results:
3
2
1
But I would like the results in ascending order, like this:
1
2
3
How can I achieve the results in ascending order with a query like this?
You can wrap the UNION in a subquery, try this:
SELECT *
FROM(
SELECT #number := 3 AS number
UNION
SELECT #number := 2 AS number
UNION
SELECT #number := 1 AS number) tmp
ORDER BY number;
Here is an SQL Fiddle example.
An edit, to explain what is happening:
In your example, MySQL is treating each group as its own query (which is how you'd expect a union to work) so it is as if you had three different queries, and only the third one is being ordered.
So, by putting the unioned queries together, you have one result set, and that entire result set is what is being ordered.
This is your query:
(select #number:=3)
union
(select #number:=2)
union
(select #number:=1)
order by #number ASC
Your order by has a constant. It is order by "1" -- #number is a variable, not a column name. Hence, no ordering. What you want is to specify the number as a column name:
select 3 as number
union all
select 2
union all
select 1
order by number;
You should also use union all instead of union, unless you want the additional overhead of removing duplicates.
I wanted to limit my query per category, I've seen a lot of same topic here but too complicated so I will ask another.
for example I have
id title category
1 one number
2 two number
3 three number
4 four number
5 a letter
6 b letter
7 c letter
and I wanted to limit my query, let say 2 per category so I have on my output like these
one
two
a
b
I got answer from diff topic
I'll post it here for others who will drop in this same question
SELECT * FROM (
SELECT
table.*,
#rn := CASE WHEN #category=category THEN #rn + 1 ELSE 1 END AS rn,
#category := category
FROM table, (SELECT #rn := 0, #category := NULL) AS vars
ORDER BY category
) AS T1
WHERE rn <= 2
Created using this link, there's an explanation there. This also works for a large number of categories, but beware, it can become very slow without the right keys defined.
set #num := 0, #category := '';
select title, category, #num := if(#category = category, #num +1, 1) as row_number,
#category := category as dummy
from test
group by category, title
having row_number <=2;
Tell me if i'm getting you right -
That's the sql -
SELECT * FROM `categories` ORDER BY `id` ASC LIMIT 0,2
What I did is this: Select all the items in categories table and order it by the id row, limit it for two results only and order it from the beggining
I have a MySql table with two columns namely category and name. I have 4 unique values of category and there are thousands of records in this table. But all these records fall into either of the 4 categories present in the table.
Now, What I want is that as output, I should get 2 results of each category i.e. 2 results of first category, then 2 results of next category and so on.
Is it possible with a single query ?
set #num := 0, #cat := '';
select category,name
#num := if(#cat = category, #num + 1, 1) as row_number,
#cat := category as dummy
from MyTable
group by cateogry, name
having row_number <= 2;
What about this?
SELECT * FROM your_table WHERE category = 1 LIMIT 2
UNION
SELECT * FROM your_table WHERE category = 2 LIMIT 2
UNION
SELECT * FROM your_table WHERE category = 3 LIMIT 2
UNION
SELECT * FROM your_table WHERE category = 4 LIMIT 2
I use MySql and I have a table like that:
| id | category | field 1 | field 2 |
Values in the category field are not unique.
I would like to fetch 5 random rows for each category value
I can't find a solution in one query for that.
Could you help me on this one?
Thank you
EDIT:
I've found this:
SELECT t.*
FROM (
SELECT #lim := 5,
#cg := -1
) vars,
table_example t
WHERE CASE WHEN #cg <> category THEN #r := #lim ELSE 1 END > 0
AND (#r := #r - 1) >= 0
AND (#cg := category) IS NOT NULL
ORDER BY
category , id
But in this case, it fetches 5 rows for each category value (but it's ordered by id). I've tried to tweak that to order this randomly but I couldn't find anything satisfying...
I am not sure that this works, just a hunch:
SET #rownum=1;
SELECT t.id,CASE WHEN #rownum > 5 THEN #rownum:=0 ELSE #rownum=#rownum+1
FROM table_example t WHERE #rownum<=5 GROUP BY t.category,t.id ORDER BY RAND()