trying to get random value from two tables using mysql? - mysql

SELECT *
FROM fixed_questions
WHERE examid = 15
ORDER BY RAND() LIMIT 1
UNION ALL
SELECT *
FROM questions
WHERE examid = 15
ORDER BY RAND() LIMIT 4;
This is my query and also i try this code. Is it possible to do that maybe i am not sure that union is worked or not for mysql.Mainly problem is random value one table get 1 and another table get 4 (that's my logic). How i do that
SELECT *
FROM v_fixed_questions vf
,v_questions vq ON (vf.examid = vq.examid)

I think the main problem is that to use LIMIT with a union it needs to be in actual subquery, and not at the outer level. It is possible to use LIMIT at the end of a union query, but then it would apply to the entire union result set, and not to one of the subqueries.
(
SELECT *
FROM fixed_questions
WHERE examid = 15
ORDER BY RAND()
LIMIT 1
)
UNION ALL
(
SELECT *
FROM questions
WHERE examid = 15
ORDER BY RAND()
LIMIT 4
);
This answer assumes that the fixed_questions and questions tables have the same number of columns (ideally with the same type). If not, then it might not make sense to ask for a union of the two full tables.

Related

MySQL - use other query condition, if another query condition returns no results

function rand(); work slow when have millions rows,
I have table 'banners'
id image type
1 name 1
2 name 4
3 name 76
19999999 name 3
need to select
select * from banners where type = 1 order by rand() limit 1
if no result then
select * from banners where type = 3 order by rand() limit 1
if no result then
select * from banners order by rand() limit 1
I try
select * from (
(select * from banners where type = 1 order by rand() limit 1) union
(select * from banners where type = 3 order by rand() limit 1) union
(select * from banners order by rand() limit 1)
) as r limit 1
but is very slow!
You can combine your queries:
select *
from banners
order by type=1 desc, type=3 desc, rand()
limit 1;
but that's still likely to have to read the entire table.
Do you have INDEX(type)? If so, that might help your first 2 SELECTs.
Provide SHOW INDEXES. It may indicate that the "cardinality" of type is such that it will 'always' or 'never' do a table scan. Also, provide EXPLAIN SELECT ... for each case.
If the index is useful and there are not many rows with type=1, that query will be relatively fast. Etc.
This discusses several ways to efficiently pick a random row. See which one applies for each of your 3 cases. Then write a Stored Routine that works something like
BEGIN
... type=1
IF a row found
RETURN...
... type=1
IF a row found
RETURN...
Return a random row from the whole table
END
select * from banners
order by Case
when Type=1 then 1
when Type=3 then 2
else 3
end asc, rand()
limit 1;

Union, order by and RAND() in mySQL

I want to have a union of two request BUT the order by rand() of the second one doesn't work..
(select * from survey
where is_priority = 1)
union all (
select * from (
select * from survey
order by rand()
) as t );
The result look like this :
I speculate that you want is_priority = 1 first followed by the rest in random order.
If so, you should not do this with union all. Just add the right keys to the order by:
select s.*
from survey s
order by (s.is_priority = 1) desc, -- put priority 1 first in the result set
rand();
Admittedly, this puts the top priority rows in random order (amongst them). But you haven't specified an order for them (and this is a non-issue if there is only one row where the priority condition is true).

Order by views limiting, then order by another column

I have a query that selects * from my database ordering by views and limiting by 4:
SELECT * FROM articles WHERE visible = 1 ORDER BY views LIMIT 4;
But in the same query I want to find all other rows ordering by column updated_at.
I haved tryied things like this, but doesn't works:
(SELECT * FROM articles ORDER BY views DESC LIMIT 4)
UNION
(SELECT * FROM articles ORDER BY updated_at DESC);
The propose this are "pinning" the 4 hotest articles on home page and then ordering by time was updated.
Have any way to ORDER BY multiple ways in the same query without repeat the rows?
How can I do this?
Continuing with your current thinking, we can take a union of two subqueries. The first subquery is what you already included in your question, and finds the 4 more frequently viewed articles. The second subquery finds everything else. The trick here is to include in each subquery a computed field which we can use to keep track of the top 4 records from everything else. Then, we order by this computed field first, followed second by the updated_at field.
(
SELECT a.*, 1 AS label
FROM articles a
WHERE visible = 1
ORDER BY views DESC
LIMIT 4
)
UNION ALL
(
SELECT a.*, 2
FROM articles a
WHERE visible = 1
ORDER BY views DESC
LIMIT 1000000 OFFSET 4 -- the limit 1000000 is arbitrary; just use a number
) -- larger than the expected size of your table
ORDER BY
label, views, updated_at
From MySQL documentation:
... The default behavior for UNION is that duplicate rows are removed from the result. ...
And
... If ORDER BY appears without LIMIT in a SELECT, it is optimized away because it will have no effect anyway. ...
So the trick here is to use limit in the second query (it is up to you to choose the limit):
(SELECT * FROM articles WHERE visible = 1 ORDER BY views DESC LIMIT 4)
UNION
(SELECT * FROM articles WHERE visible = 1 ORDER BY updated_at DESC LIMIT 100);
The query was tested in MySQL 5.6 and 5.7.
You can use a comma to separate multiple ORDERcommands.
MySQL will order from left to right.
SELECT * FROM articles WHERE visible = 1 ORDER BY views, updated_at DESC LIMIT 4;

Grab x amount of records from MySQL and get duplicates if not enough

Not really sure how to do this, but is it possible in one query to fetch x amount of records from a table, and if not enough is found, it will just randomly select duplicates.
I have a photos table, let's say it has 5 records in it, and I want to pull out 10 records and order them randomly, so I have something like:
SELECT * FROM TABLE
ORDER BY RAND()
LIMIT 10
This will just pull back 5 randomly, cos that is all I have in the table. Can I tell MySQL, hey, if you find less than 10, just randomly grab more until you reach that number?
Any help appreciated!
Thanks
This will do it:
select * from Table1
union all
select * from
(
select * from
(
select * from Table1 limit 10
union all
select * from Table1 limit 10
union all
select * from Table1 limit 10
union all
select * from Table1 limit 10
-- more unions...
) t2 order by rand()
) rand_ordered
limit 10
Union the table for as many times as your number of needed records is (10 times in this example) to make it work with only one row in the table, order the result by rand() and append it to your table with another union all.
This might not be the best performing solution tho, but it will do it.
Example here: SQLFIDDLE

SQL Distinct - Get all values

Thanks for looking, I'm trying to get 20 entries from the database randomly and unique, so the same one doesn't appear twice. But I also have a questionGroup field, which should also not appear twice. I want to make that field distinct, but then get the ID of the field selected.
Below is my NOT WORKING script, because it does the ID as distinct too which
SELECT DISTINCT `questionGroup`,`id`
FROM `questions`
WHERE `area`='1'
ORDER BY rand() LIMIT 20
Any advise is greatly appreciated!
Thanks
Try doing the group by/distinct first in a subquery:
select *
from (select distinct `questionGroup`,`id`
from `questions`
where `area`='1'
) qc
order by rand()
limit 20
I see . . . What you want is to select a random row from each group, and then limit it to 20 groups. This is a harder problem. I'm not sure if you can do this accurately with a single query in mysql, not using variables or outside tables.
Here is an approximation:
select *
from (select `questionGroup`
coalesce(max(case when rand()*num < 1 then id end), min(id)) as id
from `questions` q join
(select questionGroup, count(*) as num
from questions
group by questionGroup
) qg
on qg.questionGroup = q.questionGroup
where `area`='1'
group by questionGroup
) qc
order by rand()
limit 20
This uses rand() to select an id, taking, on average two per grouping (but it is random, so sometimes 0, 1, 2, etc.). It chooses the max() of these. If none appear, then it takes the minimum.
This will be slightly biased away from the maximum id (or minimum, if you switch the min's and max's in the equation). For most applications, I'm not sure that this bias would make a big difference. In other databases that support ranking functions, you can solve the problem directly.
Something like this
SELECT DISTINCT *
FROM (
SELECT `questionGroup`,`id`
FROM `questions`
WHERE `area`='1'
ORDER BY rand()
) As q
LIMIT 20