Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

mysql sql complicado


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.