2010-06-24 8 views
0

Voici ma requête en cours:besoin de savoir si cela est possible avec SQL et si oui, comment le faire

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 

Fondamentalement, la base de données contient des questions pour différentes rubriques. Par exemple:

questions_headings: 

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

questions: 

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

Ce que ma requête est fait au hasard sélectionne une quantité X de questions des rubriques données et leur montre à l'utilisateur.

Actuellement, si vous voulez 10 questions aléatoires (LIMIT 10), il vous donne 10 questions aléatoires à travers tous les ID. Normal, n'est-ce pas? Mais je ne veux pas ça.

Ce que j'ai besoin de faire, c'est de sortir 10 questions aléatoires réparties sur les IDs donnés. De cette façon, je ne finirai pas avec 9 questions d'un titre et une question de l'autre.

espoir qui fait sens ...

Est-il possible de le faire avec juste SQL?

+0

La distribution égale n'est pas aléatoire. – Naktibalda

+0

Je sais que cette question a peut-être été fournie simplement comme un exemple, mais il me semble que les deux tables ont une relation de 1 à 1, donc les séparer en tables séparées n'est pas nécessaire. –

+1

C'est une relation un-à-plusieurs. Une rubrique peut avoir n questions. –

Répondre

0

Si vous connaissez les rubriques lors de la création de la requête, vous pouvez faire quelque chose comme ce qui suit:

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 

L'idée est, obtenir 10/3 = 3 de chaque rubrique et obtenir les remainings (à cause de erreurs d'arrondi) de chacun d'eux. Parce que la dernière requête pourrait aboutir à des données qui ont déjà été récupérées, nous limitons de 10, donc nous obtenons certainement le 1 supplémentaire dont nous avons besoin et puis LIMITONS le tout à nouveau. Ce devrait entraîner des valeurs uniformément réparties.

+0

Le problème est que l'application recevra une quantité inconnue d'identifiants 'questions.heading'. N'y a-t-il aucun moyen de le faire avec 'SQL pur'? – dave

+0

Dans DB2, je pourrais vous écrire une requête en utilisant row_number() qui fonctionnerait, mais je ne peux pas penser à un moyen de MySQL. –

+0

Par curiosité, pourriez-vous fournir la requête? – dave

0

cela devrait fonctionner dans DB2 (et pourrait être facilement porté à d'autres bases de données supportant 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 
0

Cela fonctionne pour 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; 

Je ne peux pas tester la version MySQL , mais cela devrait fonctionner peut-être:

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:[email protected]+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; 

Le point est de commander les enregistrements de sorte qu'il y a ex poser une question à partir de chaque rubrique sélectionnée avant une deuxième question à partir de n'importe quelle rubrique sélectionnée, et ainsi de suite. S'il n'y a pas suffisamment de questions pour certaines rubriques, celles-ci seront également réparties sur les autres rubriques.

Questions connexes