需要知道这是否可以使用SQL,如果是这样,如何做到这一点

时间:2010-06-24 07:57:45

标签: php sql mysql

这是我当前的查询:

SELECT questions.question, questions_headings.title FROM questions JOIN questions_headings ON questions.heading=questions_headings.id WHERE questions.heading IN (1,2,3) ORDER BY RANDOM() LIMIT 10

基本上,数据库包含各种标题的问题。例如:

questions_headings:

+----+-------+
| id | title |
+----+-------+
| 0  | blah1 |
+----+-------+
| 1  | lol1  |
+----+-------+
| 2  | etc1  |
+----+-------+

questions:

+----+---------+----------+
| id | heading | question |
+----+---------+----------+
| 0  |   1     | howdoi   |
+----+---------+----------+
| 1  |   0     | blahques |
+----+---------+----------+
| 2  |   1     | herro    |
+----+---------+----------+

我的查询所做的是从给定标题中随机选择X个问题并将其显示给用户。

目前,如果您想要10个随机问题(LIMIT 10),它会在所有ID中提供10个随机问题。正常,对吗?但我不想要这个。

我需要查询做的是,提取分布在给定ID上的10个随机问题。这样,我不会从一个标题中得到9个问题而从另一个标题收到1个问题。

希望有意义......

是否可以仅使用SQL执行此操作?

3 个答案:

答案 0 :(得分:0)

如果您在创建查询时知道标题,则可以执行以下操作:

SELECT * FROM (
  SELECT questions.question, questions_headings.title FROM questions JOIN questions_headings ON questions.heading=questions_headings.id WHERE questions.heading = 1 ORDER BY RANDOM() LIMIT 3
  UNION
  SELECT questions.question, questions_headings.title FROM questions JOIN questions_headings ON questions.heading=questions_headings.id WHERE questions.heading = 2 ORDER BY RANDOM() LIMIT 3
  UNION
  SELECT questions.question, questions_headings.title FROM questions JOIN questions_headings ON questions.heading=questions_headings.id WHERE questions.heading = 3 ORDER BY RANDOM() LIMIT 3
  UNION
  SELECT questions.question, questions_headings.title FROM questions JOIN questions_headings ON questions.heading=questions_headings.id WHERE questions.heading IN (1,2,3) ORDER BY RANDOM() LIMIT 10
) LIMIT 10

这个想法是,从每个标题获得10/3 = 3,然后从所有标题中获取剩余部分(因为舍入错误)。因为最后一个查询可能导致已经获取的数据,我们限制为10,所以我们肯定得到我们需要的额外1,然后再次限制整个事情。 应该导致均匀分布的值。

答案 1 :(得分:0)

以下内容适用于DB2(可以轻松移植到支持row_number的其他数据库):

SELECT * FROM (
  SELECT question, title 
  FROM (
    SELECT questions.question, questions_headings.title,
      row_number() over(PARTITION BY questions.headings ORDER BY rand()) rn
    FROM questions JOIN questions_headings ON questions.heading=questions_headings.id
    WHERE questions.heading IN (1,2,3)
  )
  WHERE rn <= 3
  UNION
  SELECT questions.question, questions_headings.title
  FROM questions JOIN questions_headings ON questions.heading=questions_headings.id
  WHERE questions.heading = 1
  ORDER BY RAND() 
  FETCH FIRST 10 ROWS ONLY
)
FETCH FIRST 10 ROWS ONLY

答案 2 :(得分:0)

这适用于PostgreSQL:

SELECT q2.row - (SELECT count(*) 
                 FROM questions q3 
                 WHERE q3.heading IN (1, 2, 3)
                 AND q3.heading < q2.heading) AS ord,
       q2.heading, q2.question 
FROM (
  SELECT row_number() OVER (ORDER BY heading, random()) as row,
         q1.id, q1.heading, q1.question 
  FROM questions q1 
  WHERE heading IN (1,2,3) 
  ORDER BY heading, row) AS q2 
ORDER BY ord 
LIMIT 10;

我无法测试MySQL版本,但这可能有用:

SELECT q2.row - (SELECT count(*) 
                 FROM questions q3 
                 WHERE q3.heading IN (1, 2, 3) 
                 AND q3.heading < q2.heading) AS ord,
       q2.heading, q2.question 
FROM (
  SELECT @rownum:=@rownum+1 AS row, 
         q1.id, q1.heading, q1.question 
  FROM questions q1, (SELECT @rownum:=0) r
  WHERE heading IN (1,2,3) 
  ORDER BY heading, rand()) AS q2
ORDER BY ord 
LIMIT 10;

重点是对记录进行排序,以便在来自任何选定标题的第二个问题之前,每个选定标题中只有一个问题,依此类推。如果对某些标题没有足够的问题,它仍将平均分配给其他标题。