简体   繁体   中英

need help to construct a query with one certain result + random result

I need help on how to construct a query that will return 5 results based on a condition.
And in those 5 results, one of the records must always appear if specified on the query.
The rest will be randomly selected.

I have the tables COUNTRY, CATEGORY, QUESTIONS
For COUNTRY I have the records: CANADA, CHINA, FRANCE, GERMANY, JAPAN, USA
For CATEGORY I have the records: CAPITAL, LANDMARKS, FLAG, LANGUAGE

Each question is categorized based on CATEGORY and COUNTRY.
Now I want a question with CATEGORY "CAPITAL" to always appear on the results whenever I select a country.
So if I select FRANCE, 5 questions ABOUT FRANCE must be selected where one of the result has the category CAPITAL and the other 4 are randomly selected.

my solution is to have 2 questions but I don't know if it's correct:

SELECT * FROM QUESTIONS WHERE COUNTRY = "FRANCE" AND CATEGORY = "CAPITAL"

and

SELECT * FROM QUESTIONS WHERE COUNTRY = "FRANCE" AND CATEGORY != "CAPITAL" ORDER BY RAND() LIMIT 4

then just append the results.
I have also heard from somewhere that using the RAND() function has a downside on it because it must sort the records before before it can pick random records. So it is not good to use if you have thousands of records.
So if there is a better way to do this and if anyone could help, I would appreciate it a lot.
Thanks in advance.

Why not just add another column to indicate that row is higher priority?

Select * from Colors order by priority DESC, Rand() limit 5

Or if there are very specific conditions, you can code them like this:

SELECT * FROM Colors
ORDER BY IF(ColorName = 'Green', 100, IF(_other_conds_if_any_, 99, 0)) DESC,
    Rand()
LIMIT 5

Update

I keep suggesting the same solution. Ok, I'll try to elaborate a bit more. What is best IMO, is to add a column "sticky" to your table (in your case that would be QUESTIONS).

ALTER TABLE `QUESTIONS` ADD COLUMN `sticky` TINYINT NOT NULL DEFAULT 0;

Then mark needed questions as sticky (make admin UI for that or just run raw query yourself)

UPDATE `QUESTIONS` SET `sticky` = IF(`CATEGORY` = "CAPITAL", 1, 0);

And then select your questions like this:

SELECT *
FROM `QUESTIONS`
WHERE `COUNTRY` = "FRANCE"
ORDER BY `sticky` DESC, RAND()
LIMIT 5;

It would be best to make an admin UI to specify conditions on what questions are sticky, and run it after adding a question too. It is good for frequent selections. If new questions are being added frequently then it would be better to put the condition directly into ORDER clause (no need to add that column then), or add the column to category table instead and JOIN it.

#1. don't add any column and put condition into ORDER clause
SELECT *
FROM `QUESTIONS`
WHERE `COUNTRY` = "FRANCE"
ORDER BY IF(`CATEGORY` = "CAPITAL", 1, 0) DESC, RAND()
LIMIT 5;

#2. add column to categories table
SELECT q.*
FROM `QUESTIONS` q
    INNER JOIN `CATEGORIES` cat ON (cat.`CATEGORY_NAME` = q.`CATEGORY`)
    #unsure what your conditions would be here as Idon't know your DB structure
WHERE q.`COUNTRY` = "FRANCE"
ORDER BY cat.sticky DESC, RAND()
LIMIT 5;

This is very similar to what you have, but it looks fine to me:

Select * from Colors where ColorName = 'Green'
UNION
SELECT * FROM (Select * from Colors where ColorName != 'Green' order by Rand() limit 4)

Another way would be a CASE statement in your query:

SELECT *,
  CASE ColorName
    WHEN 'green' THEN 2
    ELSE RAND()
  END AS r
FROM Colors ORDER BY r DESC LIMIT 5

But I guess that doing two queries is actually faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM