2012-04-17 4 views
2

Я задал вопрос сегодня и получил хороший ответ, который хорошо работает. Была вторая часть вопроса, который так и не получил ответа, поэтому я снова пытаюсь.mysql complex sql

SELECT q.id,q.question,a.question_id,a.answer, a.correct 
FROM (SELECT * FROM questions q WHERE q.subject_id = 18 
     ORDER BY RAND() LIMIT 5) q 
JOIN answers a on q.id = a.question_id GROUP BY q.id, a.id 

Вышеуказанное прекрасно и возвращает 5 случайных вопросов вместе с соответствующими ответами. Проблема в том, что каждый вопрос имеет 9 ответов, 1 из которых правильный (правильный = 1), а остальные ложные (правильный = 0). Мне не нужны все ответы, а скорее правильные и три других случайных.

Я играю с этим часами и никуда не уйду.

Любая помощь будет оценена по достоинству.

Благодаря

Стив

PS: Может быть, это лучше, чтобы справиться с этим с помощью PHP, но я снова не уверен. Любые мысли об этом тоже будут полезны.

+0

Я попытался выполнить ваш другой вопрос, но так и не смог получить рабочее решение. Вот насколько я добрался, если другие захотят обратиться за помощью: http://www.sqlfiddle.com/#!2/34906/34. По какой-то причине «ORDER BY RAND()» во внутреннем запросе «ответов» не работает. – mellamokb

+1

Вы бы лучше в PHP. У MySQL нет языковых конструкций, которые вы можете использовать в Oracle/SQL Server/PostgreSQL. – gbn

+0

@gbn: Я согласен, тем более, что на вопрос только до 9 ответов. Так же легко вытащить все ответы на PHP и сделать рандомизацию там. – mellamokb

ответ

2

Это еще один пример записей TOP X на пример Y. По каждому вопросу вы хотите получить 4 ответа. ПРЕДУПРЕЖДЕНИЕ на самом деле требуется ДВАЖДЫ ... Сначала ограничить квалификационные вопросы, а еще один «рейтинг» ответов, который гарантирует, что «Правильный ответ» ВСЕГДА будет включен в набор результатов каждого вопроса.

Таким образом, мой подход заключается в том, чтобы применить случайное отношение к первым вопросам, чтобы получить это как результат подмножества, затем присоединить это к ответам и ограничить X на Y. Тогда мы получим все это. Критическая вещь здесь заключается в том, что внутренний запрос должен быть заказан по идентификатору вопроса ... И определитель «Правильный ответ» всегда находится в первой позиции, но все после рандомизации включает в себя в общей сложности 4 записи.

Затем окончательный запрос применяет предложение WHERE, чтобы включать только то, где ранжирующая последовательность равна < = 4 (из возможных ответов на все 9 ответов включено для 1 вопроса, но затем применяется окончательное предложение «ORDER BY», чтобы сохранить вопросы вместе, но рандомизирует ответы, поэтому «Правильно» больше не всегда возвращается в первую позицию.Вы можете удалить это внешнее предложение ORDER BY для целей тестирования только для подтверждения функциональности, а затем добавить его позже.

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() 

пару небольших изменений ... Убедитесь, что на SQLVars имеет := для каждого из заданий. Когда я изначально был отправлен, я оставил одно сообщение «:», которое могло вызвать ложную ошибку. Я также квалифицировал внутренний «Order by», используя «a.correct = 1» (не имел ссылки на псевдоним). Наконец, изменилось внешнее предложение WHERE только на < 5 вместо <= 4. Я много сделал из этих величайших X на группы Y и знаю, что они работают, просто пропуская что-то простое, я уверен.

Кроме того, скорректировано случайное значение IF(), чтобы иметь первое значение как десятичное значение, в противном случае все randoms будут установлены в 1 (целое число) и никогда не будут делиться ... Также для возможных проблем, когда применяется ЗАКАЗ, -подтвердите все Q и A, предварительно отсортированные, чтобы получить все правильные ответы в первой позиции, затем примените SQLVars к этому набору, затем завершите последовательность рангов и порядок.

+0

Я пробовал ваше предложение и получил следующую ошибку ... # 1064 - У вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее версии сервера MySQL, для правильного синтаксиса для использования рядом с QWithAllAnswers, где QWithAllAnswers.ARankSeq <= 4 order by Q 'по строке 27 – SteveF

+0

@ user1292262, см. комментарии к исправленным ответам и настройкам sql. – DRapp

+0

Я исправил некоторые опечатки и построил ваше решение здесь: http://www.sqlfiddle.com/#!2/34906/52. Я знаю, на каком примере вы смоделировали, и я подумал о том же. Но похоже, что он страдает от тех же самых проблем, которые у меня были в моем собственном решении, которое я сделал и опубликовал в качестве комментария к OP. Он по-прежнему не рандомизирует ответы по какой-то нечетной причине, а просто берет первые четыре ответа от каждого вопроса. Настолько странно. Может быть, это проблема только с sqlfiddle.com или версией MySQL, используемой там? У меня нет экземпляра MySQL, который доступен для тестирования ... – mellamokb

0

Вы можете попробовать использовать подзапросы, как:

(псевдокод)

Select a.*, q.* 
from questions q join answers a on q.id=a.question_id 
where q.id in (SELECT id FROM questions q1 WHERE q1.subject_id = 18 ORDER BY RAND() LIMIT 5) 
and a.id in (SELECT id FROM answers a1 WHERE a1.question_id = q.id ORDER BY a1.correct desc, RAND() LIMIT 4) 

(конец псевдокод)

Это могло бы быть более эффективным, чтобы прочитать все ответы, и выбрать случайные те в вашем коде (все же их можно заказать по correct по убыванию, , чтобы вы знали, первый из них правильный).

+1

Спасибо всем за помощь. Похоже, что консенсус заключается в рандомизации в php. Я дам, что пойду и посмотрю, как я нахожусь. Причина, по которой я хочу получить все вопросы и ответы за один раз, состоит в том, что вопросы должны быть уникальными, поэтому я не могу получить их по одному. Они должны быть уникальными для всего теста. Надеюсь, это имеет смысл. – SteveF

+1

Простейшим решением является получение вопросов в одном запросе, а затем получение ответов для каждого вопроса в отдельном запросе. –

1

Попробуйте это:

SELECT q.id,q.question,a.question_id,a.answer, a.correct 
FROM (SELECT * FROM questions q WHERE q.subject_id = 18 
     ORDER BY RAND() LIMIT 5) q 
JOIN answers a on q.id = a.question_id 
ORDER BY q.id, a.correct, RAND() 

что вы должны получить правильный ответ первым, а затем ложные ответы в случайном порядке. Это должно облегчить вам выбор 1 + 3 в вашем php-коде.

Редактировать: Я удалил вашу группу и поместил ее в порядок вместо этого, как вы хотите ответить на один ряд pr.

1

Почему бы не использовать UNION, чтобы получить хорошие ответы и случайные неправильные ответы?

SELECT q.id,q.question,a.question_id,a.answer, a.correct 
FROM (SELECT * FROM questions q WHERE q.subject_id = 18 
     ORDER BY RAND() LIMIT 5) q 
    JOIN answers a on q.id = a.question_id 
WHERE a.correct = 0 
GROUP BY q.id, a.id 

UNION 

SELECT q.id,q.question,a.question_id,a.answer, a.correct 
FROM question q 
    JOIN answers a on q.id = a.question_id 
WHERE q.subject_id = 18 
    AND a.correct = 1