Как заставить этот подзапрос работать? - PullRequest
0 голосов
/ 30 декабря 2010

Я пытаюсь сделать это одним запросом.Я задавал подобный вопрос несколько дней назад, но мои личные требования изменились.

У меня есть веб-сайт типа игры, где пользователи могут посещать "занятия".В моей БД три таблицы.

Я использую MySQL.У меня есть четыре таблицы:

  • hl_classes (int id, int Professor, класс varchar, текстовое описание)
  • hl_classes_lessons (int id, int class_id, varchar lessonTitle, varchar lexiconLink, текст)
  • hl_classes_answers (int id, int lesson_id, int student, текст submit_answer, int процент)

hl_classes хранит все классы на сайте.

Уроки являются индивидуальными уроками для каждого класса.Класс может иметь бесконечные уроки.Каждый урок доступен в определенном термине.

hl_classes_terms хранит список всех терминов, и у текущего термина есть поле active = '1'.

Когда пользователь отправляет свои ответы наурок хранится в hl_classes_answers.Пользователь может ответить на каждый урок только один раз.Уроки должны отвечать последовательно.Все пользователи посещают все «классы».

Я пытаюсь сделать следующий урок для каждого пользователя в каждом классе.Когда пользователи начинают, они находятся в семестре 1. Когда они заканчивают все 10 уроков в каждом классе, они переходят к семестру 2. Когда они заканчивают урок 20 для каждого класса, они переходят к семестру 3. Допустим, мы знаем термин, которым является пользователь.с помощью переменной PHP $ term.

Так что это мой запрос, который я сейчас пытаюсь удалить, но он не работает.В частности, потому что hC.id неизвестно в предложении WHERE

SELECT hC.id, hC.class, (SELECT MIN(output.id) as nextLessonID
  FROM ( SELECT id, class_id
   FROM hl_classes_lessons hL
   WHERE hL.class_id = hC.id
   ORDER BY hL.id
   LIMIT $term,10 ) as output
  WHERE output.id NOT IN (SELECT lesson_id FROM hl_classes_answers WHERE student = $USER_ID)) as nextLessonID
FROM hl_classes hC

Моя логика, лежащая в основе этого запроса, является первой для каждого класса;выберите все уроки в термине, в котором находится текущий пользователь. Из этого рассортируйте уроки, которые пользователь уже сделал, и получите МИНИМАЛЬНЫЙ идентификатор уроков, которые еще предстоит сделать.Это будет урок, который должен сделать пользователь.

Надеюсь, я прояснил свой вопрос достаточно ясно.

Ответы [ 2 ]

2 голосов
/ 30 декабря 2010

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

Чтобы сделать это с какой-либо эффективностью (и ИМХО здравым смыслом), вам нужно сначала пересмотреть структуру таблицы и предположения о ваших данных.Исходя из структур таблиц, которые вы предоставили, и того, как вы описали номера уроков, я предполагаю, что, например, будет 1 класс, уроки 1, 2, 3, ..., 10, 11, ... 20, 21, ..., 30, а затем класс 2, уроки 1 ... 30, а затем класс 3, уроки 1 ... 30 и т. Д. Кроме того, уроки 1-10 для каждого класса соответствуют термину 1, 11-20, к термину 2, и 21-30 к термину 3. Наконец, термины завершаются в порядке - урок 10 класса 3 завершается перед уроком 11 класса 1.

Сначала, вместо того, чтобы использовать номер вашего класса в качестве обоихуникальный идентификатор и порядковый номер (класс 1 встречается раньше, чем класс 2 и т. д.), я бы предложил поле уникального идентификатора (возможно, с автоматическим приращением) и отдельное поле class_num для порядкового номера.(Это менее критично для таблицы классов, чем для таблицы уроков, описанной далее.)

Далее, и аналогично, уроки должны получать поле уникального идентификатора отдельно от поля номера урока.Идентификатор будет PK.Этот уникальный идентификатор необходим, чтобы значительно упростить требуемый запрос, а также любые другие запросы, которые могут вам понадобиться.Без этого вы имеете дело с составным ключом с двумя полями, который усложняет множество соединений и подзапросов.Вы, вероятно, захотите дополнительный уникальный индекс для class_id и lesson_num, чтобы номер урока не использовался повторно для класса.Кроме того, эта таблица должна содержать term_num (или term_id), которому назначен конкретный урок для определенного класса.Это избавит вас от необходимости подсчитывать, какой термин используется в уроке, используя слишком сложную формулу MOD.Это было бы излишним.Просто сохраните номер термина с информацией об уроке, и вы сможете упорядочить термины по своему усмотрению.

Далее, поле id таблицы ответов должно быть уникальным с автоматическим приращением.Если это важно, вам также может потребоваться уникальный индекс для lesson_id и student_id (хотя это означает, что либо не повторяется, либо перезаписывается) .

Итак, теперь у меня есть:

  • hl_classes (int id, int class_num, профессор, имя_класса, описание) PK: id, autoinc
  • hl_classes_lessons (int id, int class_id, int lesson_num, int term_num, l_title, l_link, l_data)ПК: id, autoinc;Уникальный ключ: class_id, lesson_num
  • hl_classes_answers (int id, int lesson_id, int student, ans, pct) PK: id, autoinc;Уникальный ключ: lesson_id, student

С этим я придумал:

select hC.id as next_class_id, hL.id as next_lesson_id, hC.class as next_class, hL.term_num as term_num, hC.class_num as next_class_num, hL.lesson_num AS next_lesson_num
from hl_classes hC
left join hl_classes_lessons hL on hL.class_id = hC.id
where hL.term_num = $TERM_NUM
and hL.id not in (
    select hA.lesson_id
    from hl_classes_answers hA
    where student = $USER_ID
)
order by hC.class_num, hL.lesson_num
limit 1;

Это вернет вам либо одну строку, содержащую соответствующую информацию о следующем классе для этогостудент, учитывая этот термин, или все нули.Обратите внимание, что идентификаторы не для отображения, так как они могут быть любым старым числом.Вы бы отобразили поля _num.

0 голосов
/ 30 декабря 2010

Я не уверен, как вы хотите, чтобы конечный результат выглядел, и почему в вашем запросе есть термин LIMIT $, но если вы хотите получить все классы и следующий урок (если он доступен) для пользователя, которого вы можно использовать это:

SELECT c.*, l.*
FROM hl_classes c JOIN (
        SELECT l.class_id, MIN(l.id) NextLessonID
        FROM hl_classes_lessons l LEFT JOIN (
                SELECT sca.class_id, MAX(sca.lesson_id) MaxID
                FROM hl_classes_answers sca
                WHERE sca.student = $USER_ID
                GROUP BY sca.class_id
            ) cm ON (l.class_id = cm.class_id AND l.id > cm.MaxID) OR cm.class_id IS NULL
        GROUP BY l.class_id
    ) nid ON c.id = nid.class_id
    JOIN hl_classes_lessons l ON c.id = l.class_id AND l.id = nid.NextLessonID
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...