I need to select a record at random but not one already selected before unless all records have been selected.
Table Setup:
_word (id, nam)
_word_tm (id, word_id, tm)
Every time a word is used it is loaded into _word_tm. What I am wanting to do is make sure I use all the words before I reuse an already used word.
What I am really looking for is something like the below but just trying to figure out how to mesh.
select w.nam FROM _word w LEFT JOIN _word_tm wt ON w.id = wt.word_id ORDER BY count(wt.id) asc, rand() limit 1
First, find out how many times the least-used words have been used:
select _word.id, count(*) c from _word
left join _word_tm on _word.id=_word_tm.word_id order by c limit 1;
Store that value (from c) in a variable $least_used. Then get all the words used that many times, in random order:
select _word.id, count(*) c from _word
left join _word_tm on _word.id=_word_tm.word_id
group by _word.id having c <= {$least_used}
order by rand() limit 1;
You should be able to do something like this:
SELECT * FROM word_table WHERE word NOT IN (SELECT word FROM words_used) ORDER BY rand() LIMIT 1;
You will need to have an updated copy of MySQL for this to work. Also, you would need to include a line of code afterward or before hand to clear/reset your words_used table once it had the same contents as word_table.
You can try the following SQL to return a random row
select A.nam
from _word A
where A.id not in (select B.id from _word_tm B)
order by rand()
limit 1
if the above does not return any reocrd , do a simple
select A.nam
from _word A
order by rand()
limit 1
Related
select d.order_type from migu_td_aaa_order_log_d d where exists(select 1
from migu_user r where r.user_id = '156210106' and r.user_num =
d.serv_number) and d.product_id in ('2028594290','2028596512','2028597138' )
order by d.opr_time desc limit 1
why the above sql failed ,indicates :
FAILED: SemanticException [Error 10002]: Line 4:11 Invalid column reference 'opr_time'
but the below one works :
select temp.order_type from (
select d.* from migu_td_aaa_order_log_d d where exists(select 1 from
migu_user r where r.user_id = '156210106' and r.user_num = d.serv_number)
and d.product_id in ('2028594290','2028596512','2028597138' ) order by
d.opr_time desc limit 1) temp;
this one works fine ,too ,and much more efficient than the second one:
select d.* from migu_td_aaa_order_log_d d where exists(select 1 from
migu_user r where r.user_id = '156210106' and r.user_num = d.serv_number)
and d.product_id in ('2028594290','2028596512','2028597138' )
order by d.opr_time desc limit 1
I only need to get order_type field,so even though the second one works,but it cost much more time.
Can anyone help me?
Thanks a lot!
Your first query does not work because, in the first select statement, you are just getting one column (d.order_type), but you are trying to order by another column (d.opr_time), which you have not included in your select statement
select d.order_type from ...
...
order by d.opr_time desc limit 1
Note that if you added the column d.opr_time to your first query, it would work:
select d.order_type, d.opr_time from ...
...
order by d.opr_time desc limit 1
Your second query works because, in the subquery, you have selected all the columns of d (d.*), so when you order by opr_time, that column is present. (Same for the third query).
select temp.order_type from (
select d.* ... order by d.opr_time ...
EDITED:
According to the Hive documentation:
When using group by clause, the select statement can only include
columns included in the group by clause. Of course, you can have as
many aggregation functions (e.g. count) in the select statement as
well.
So, this query:
select d.order_type, d.opr_time from ...
...
order by d.opr_time desc limit 1
Shouldn't work either, because the select clause has an additional column (d.order_type) that is not included in the group by clause.
I hope this helps.
P.S. This answer about SQL execution order might be useful.
1.
Hive currently have an order by limitation.
The current status of this issue is PATCH AVAILABLE.
see -
"Can't order by an unselected column"
https://issues.apache.org/jira/browse/HIVE-15160
2.
You might want to get familiar with LEFT SEMI JOIN which is a cleaner syntax for EXISTS
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Joins#LanguageManualJoins-JoinSyntax
3.
using min / max over a struct / named_struct can be used instead of order by ... asc / desc and limit 1
Here is an alternative solution:
select max(named_struct('opr_time',d.opr_time,'order_type',d.order_type)).order_type
from migu_td_aaa_order_log_d d
left semi join migu_user r
on r.user_num =
d.serv_number
and r.user_id = '156210106'
where d.product_id in ('2028594290','2028596512','2028597138')
;
P.s.
You seriously want to consider to treat IDs (user_id, product_id) as numeric and not as strings.
I have a query which does the job but instead of the trans_inventory (which is an ID of the location) I need to get the location_name.
This one is working to get the id
SELECT *
FROM {TABLE}
WHERE trans_product = 646
ORDER BY trans_date2 DESC Limit 1
But I wonder if I can do it this way, somehow embed the location table, I have tried but below doesn't work
SELECT *, site_location.location_name
FROM site_trans
cross join
(select *
From site_location)
site_location
WHERE trans_product=646 ORDER BY trans_date2 DESC Limit 1
sl.location in the JOIN must be the site_location location id field name - I used locastion_id but it might be likely id as well. I used LEFT JOIN to avoid missing site_trans in case there is no matching location id.
SELECT s.*, sl.location_name
FROM site_trans AS s
LEFT JOIN site_location AS sl ON sl.location_id = s.location_id
WHERE s.trans_product=646
ORDER BY s.trans_date2 DESC
Limit 1
SELECT * FROM
MobileApps as dtable
WHERE (SELECT COUNT(*) as c
FROM app_details
WHERE trackId=dtable.SourceID)=0
ORDER BY id ASC
LIMIT 0,2
Problem is say the first two results ordered by id are in app_details, so the COUNT(*) doesnt' equal to 0 for the first two results. But there are much more results available in MobileApps table that would equal to 0.
I supposed it would first SELECT * FROM app_details WHERE trackId=dtable.SourceID)=0 and then ORDER BY id ASC LIMIT 0,2, not the other way around, what is a possible way to get it around ?
Thanks
Your query works, but a better way to write it is:
SELECT dtable.*
FROM MobileApps dtable
LEFT JOIN app_details d ON d.trackId = dtable.SourceID
WHERE d.trackId IS NULL
ORDER BY dtable.id
LIMIT 0, 2
or:
SELECT *
From MobileApps dtable
WHERE NOT EXISTS (SELECT *
FROM app_details d
WHERE d.trackId = dtable.SourceID)
ORDER BY id
LIMIT 0, 2
See all 3 versions here: http://www.sqlfiddle.com/#!2/536db/2
For a large table, you should probably benchmark them to see which one MySQL optimizes best.
i have two tables raw_materials and raw_materials_moves.
raw_materials has fields
id, name
raw_materials_moves has this fields
id, raw_material_id, price, created
so, i need to select last 3 moves of each raw material
i have this query but doesn´t work
SELECT a.*, b.price, b.created
FROM raw_materials a
LEFT JOIN
(SELECT price, raw_material_id, created FROM raw_material_moves ORDER BY created DESC LIMIT 3) b
ON b.raw_material_id=a.id
ORDER BY a.id
I would agree mostly with #chetan on the usage of variables to get this job done.
Here is one of the best articles that I have come across on the subject and different ways to handle it.. ranging from easy to hard.
i will suggest you to user cursor with DESC (or) by fetching in reverse order
SELECT r1.id,name,raw_material_id
FROM raw_materials r1, raw_materials_move r2
WHERE r1.id=r2.id ORDER BY DESC LIMIT 3;
last 3 moves by created (I assume date) of each raw material
select * from
(select a.id,a.price,a.created,
if(#mat=a.raw_material_id,#num:=#num+1,#num:=1) rank,
#mat:=a.raw_material_id
from raw_materials_moves a, (select #num:=0) b
order by a.raw_material_id,a.created desc) temp
where rank <=3;
see demo here
Reverse-sort it (i.e. ... SORT BY somefield DESC) and then get the first 3 (by appending LIMIT 3)
I have the following MySQL. I want to pull the data in random order.
Could anyonet teach me how to do it please.
$Q = $this->db->query('SELECT P.*, C.Name AS CatName
FROM products AS P
LEFT JOIN categories C
ON C.id = P.category_id
WHERE C.Name = "Front bottom"
AND p.status = "active"
');
$Q = $this->db->query('SELECT P.*, C.Name AS CatName
FROM products AS P
LEFT JOIN categories C
ON C.id = P.category_id
WHERE C.Name = "Front bottom"
AND p.status = "active"
ORDER BY RAND()
');
you can use the RAND function of MySQL to do that, to be noted that it would perform really slowly on huge dataset (~ about 10k). MySQL would pickup a random number for each row of the table which could lead to problem if the table is huge.
A safer method would be to do a SELECT count(*) as n FROM table and to pickup a random number and do a query with LIMIT 1,n to pickup the nth row. That would work if you need only 1, or you don't care having the result in same order.
After if you really need a complete random set better to do it on server side in my opinion.
You can try
ORDER BY RAND()
The easiest way is using ORDER BY RAND(), but it's performance is miserable, especially for larger datasets (requires a random number for all matching rows).
Another way is randomly creating ids(Either in your code or using RAND() again: WHERE id in (RAND(), RAND(), RAND(), RAND()) should work, but no guarantee). This gets problematic as soon as some IDs don't exist.
Here is an interesting article on the topic.