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()
Related
I will appreaciate any help on this issue. I already spent hours without any real solution.
I have a SQL
SELECT to_place, rank
FROM
(SELECT g1.to_place as to_place, g1.pcount as pcount,
#rank := IF(#current_to_place = g1.to_place, #rank + 1, 1) AS rank,
#current_to_place := g1.to_place
FROM
(select
to_place, count(*) as pcount
from temp_workflows
group by to_place
order by to_place,pcount desc) g1
ORDER BY g1.to_place, g1.pcount DESC) ranked
In table g1, I am grouping my data to find the most common occurrence of to_place.And then I want to rand those occurrences in ascending order (so I can later select top 3 of the most common occurrences per each to_place category.
The issue is that the user-defined variable is unpredictable (#rank is sometimes always 1) which probably is related to the fact that in one statement, I should not reference the same variable (current_to_place). I read a lot about using separate statements etc. but I could find a way to write my statement in a different way. How can I define #current_to_place elsewhere so the result is the same?
Thanks in advance for your help.
I think you should be testing pcount to get rank and you should initialise variables
DROP TABLE IF EXISTS T;
CREATE TABLE T
(to_place int);
insert into t values (1),(2),(2),(3),(3),(3);
SELECT to_place, rank
FROM
(
SELECT g1.to_place as to_place, g1.pcount as pcount,
#rank := IF(#current_to_place <> pcount, #rank + 1, 1) AS rank,
#current_to_place := pcount
FROM
(select
to_place, count(*) as pcount
from t
group by to_place
order by to_place,pcount desc) g1
cross join(select #rank:=0,#current_to_place:=0) r
ORDER BY g1.pcount DESC
)
ranked
+----------+------+
| to_place | rank |
+----------+------+
| 3 | 1 |
| 2 | 2 |
| 1 | 3 |
+----------+------+
3 rows in set (0.016 sec)
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
id | count
1 | 1
3 | 1
5 | 1
2 | 2
4 | 3
I’d like to know previous and next record.
The record after id ‘5’ is id ‘2’.
So I make this query.
select id from test
where id != 5 and count > 1
LIMIT 1
The result is ok but if I want to know the record after id ‘3’, it returns id ‘2’. I expected id ’5’.
So I changed that query.
select id from test
where id != 5 && count >= 1
LIMIT 1
But it returns the wrong result again.
It returns id ‘1’
How can I get the previous or next record if there are same values?
Please let me know.
It seems that you're ordering by count?
If you want to select the next value of 5, It should be like this:
1. First, you need to add an order number to your result.
2. Then get the result you want by filtering the row_number.
SELECT row_number
FROM
(SELECT id, #rownum := #rownum + 1 as row_number
FROM test
CROSS JOIN (SELECT #rownum := 0) r ORDER by count) T1
WHERE id = 5
INTO #concreate_order_number;
SELECT id
FROM
(SELECT id, #rownum := #rownum + 1 as row_number
FROM test
CROSS JOIN (SELECT #rownum := 0) r ORDER by count) T2
WHERE row_number > #concreate_order_number
LIMIT 1;
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