Este é outro exemplo de registros TOP X por exemplo Y. Para cada pergunta, você quer 4 respostas. Um LIMITE é realmente necessário DUAS VEZES... Primeiro para limitar as perguntas de qualificação, e outro "ranking" de respostas que garante que a resposta "Correta" seja SEMPRE incluída por conjunto de resultados de perguntas.
Então, minha abordagem é aplicar o aleatório contra as perguntas primeiro para obter isso como um resultado de subconjunto, depois juntá-lo às respostas e limitar X por Y. ENTÃO, podemos resumir tudo. O crítico aqui é que a consulta interna deve ser ordenada pelo ID da pergunta... E o qualificador, a resposta "correta", está sempre na primeira posição, mas qualquer coisa depois é randomizada para incluir um total de 4 registros.
Em seguida, a consulta final aplica a cláusula WHERE para incluir apenas onde a sequência de classificação é <=4 (das possíveis todas as 9 respostas incluídas para 1 pergunta, mas aplica uma cláusula final "ORDER BY" para manter as perguntas juntas, mas randomiza as respostas para que o "Correto" não seja mais sempre retornado na primeira posição. Você pode remover essa cláusula "ORDER BY" externa para fins de teste apenas para confirmar a funcionalidade e adicioná-la novamente mais tarde.
select
FinalQA.*
from
( select
QWithAllAnswers.*,
@RankSeq := if( @LastQuestion = QWithAllAnswers.id, @RankSeq +1, 1 ) ARankSeq,
@LastQuestion := QWithAllAnswers.id as ignoreIt
from
( SELECT
q.id,
q.question,
q.RandQuestionResult,
a.question_id,
a.answer,
a.correct
FROM
( SELECT q.ID,
q.Question,
q.question_ID,
RAND() as RandQuestionResult
FROM
questions q
WHERE
q.subject_id = 18
ORDER BY RAND()
LIMIT 5) JustQ
JOIN answers a
on q.id = a.question_id
ORDER BY
JustQ.RandQuestionResult,
if( a.correct = 1,0.000000, RAND()
) QWithAllAnswers,
( select @RankSeq := 0, @LastQuestion := 0 ) SQLVars
) FinalQA
where
FinalQA.ARankSeq < 5
order by
FinalQA.RandQuestionResult,
rand()
Algumas pequenas mudanças... Certifique-se no
SQLVars
tem :=
para cada uma das atribuições. Quando postei originalmente, deixei um ":" desativado, o que poderia ter gerado um erro falso. Também qualifiquei o "Order by" interno usando "a.correct =1" (não tinha referência de alias). Por fim, alterei a cláusula WHERE externa para apenas < 5
em vez de <= 4
. Eu fiz MUITOS desses grandes agrupamentos X por Y e sei que eles funcionam, só falta algo simples, tenho certeza. Além disso, ajustou o
IF()
random para ter o primeiro valor como um decimal, caso contrário, todos os aleatórios são definidos como 1 (número inteiro) e nunca fração ... Também para possíveis problemas de quando o ORDERING é aplicado, eu pré-consultei todos os Q e A pré-ordenados para obter todas as respostas corretas na primeira posição, ENTÃO aplique o SQLVars
contra esse conjunto e, em seguida, finalize a sequência de classificação e a ordenação.