Mysql запрос проблема - PullRequest
       12

Mysql запрос проблема

1 голос
/ 26 мая 2011

У меня проблема с моим запросом mysql.

Моя база данных:

sections
id
section_name

grades
id
user_id
section_id
date
grade

Я хочу, чтобы мои данные отображались так:

Оценка_секции

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

SELECT *

                        FROM 
                        grades, 
                        sections 

                        WHERE 
                        sections.id = grades.section_id

                        AND
                        grades.user_id = '.$id.'

                        GROUP BY grades.section_id

                        ORDER BY grades.date DESC

РЕДАКТИРОВАТЬ: переменная $ id является идентификатором пользователя из сеанса.

Ответы [ 8 ]

1 голос
/ 26 мая 2011

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

select STRAIGHT_JOIN
      PreQuery.Section_ID,
      Sections.section_name,
      PreQuery.LastDatePerSection
   from
      ( select section_id, 
               user_id,
               max( date ) as LastDatePerSection 
            from
               grades
            where
               user_id = YourUserIDParameter
            group by
               section_id ) PreQuery

      join sections
         on PreQuery.Section_ID = Sections.ID

      join grades
         on PreQuery.Section_ID = grades.Section_ID
         AND PreQuery.User_ID = grades.User_ID
         AND PreQuery.LastDatePerSection = grades.Date
1 голос
/ 26 мая 2011

Мое решение заключается в использовании подзапроса для получения идентификатора последней оценки, а затем передачи его в запрос, который затем объединяет таблицы разделов и оценок, чтобы вернуть имя_сектора и оценку. Пожалуйста, рассмотрите это скорее как psuedocode, чем действительный SQL-запрос, так как у меня нет времени на его тестирование. Возможно, вернусь позже, чтобы отредактировать его

SELECT section_name, grade FROM sections, grades WHERE sections.id = grades.id AND grades.id = (SELECT id FROM grades WHERE section_id = '$Id' ORDER by date DESC LIMIT 1)

0 голосов
/ 26 мая 2011

Предположим, что мы ищем оценки пользователя с id = 1 (просто для проверки запроса без php). Вы можете заменить его на $ Id позже.

Если ваш столбец дат достаточно точен, чтобы обеспечить его уникальность для каждой оценки, которую вы можете использовать:

SELECT s.section_name, g1.grade FROM
  ( SELECT g.section_id, max(g.date) AS last_grade_date
    FROM grades g
    WHERE g.user_id = 1
    GROUP BY g.section_id ) gd
  JOIN grades g1
    ON g1.date = gd.last_grade_date
  JOIN sections s
    ON s.id = gd.section_id

Если ваша дата не уникальна, вы должны присоединить оценки к себе по идентификатору, найденному в зависимом подзапросе:

SELECT s.section_name, ga.grade FROM
  ( SELECT g1.section_id, max(g1.date) AS last_grade_date
    FROM grades g1
    WHERE g1.user_id = 1
    GROUP BY g1.section_id ) gmax
  JOIN grades ga
    ON ga.id =
      ( SELECT g2.id
        FROM grades g2
        WHERE g2.user_id = 1
        AND g2.section_id = gmax.section_id
        AND g2.date = gmax.last_grade_date
        LIMIT 1 )
  JOIN sections s
    ON s.id = gmax.section_id

Для этого запроса необходим индекс (user_id, section_id, date).

ALTER TABLE grades ADD INDEX user_section_date( user_id, section_id, date ) ;

@ Комментарий: Хорошо, я попытаюсь объяснить второй запрос, поскольку он дает правильные результаты для любого случая.

В таблице g1 мы берем строки из оценок для пользователя с id = 1, мы группируем их по разделам и в каждом разделе мы находим максимальную дату - что означает самую последнюю дату. На данный момент мы еще не знаем, какая строка в точности содержит эту самую последнюю дату, потому что мы можем выбрать только столбцы, которые находятся в group by или в агрегатных функциях (например, max ()). Mysql позволяет выбирать другие столбцы, такие как класс, называемые скрытыми столбцами (другие dbs просто выдают синтаксическую ошибку), но он может возвращать любую строку из каждой группы, обычно не ту, которую мы хотим, и мы хотим, чтобы та содержала самую последнюю Дата. Если все строки имеют одинаковое значение, как, например, user_id в этом случае, это нормально, но нам нужны оценки, которые могут быть разными в каждой группе. Для небольших таблиц select может вернуть правильную, поэтому некоторые люди утверждают, что упорядочение по дате может помочь, потому что они проверяют его на небольших таблицах и видят правильные результаты, но это происходит неправильно, когда таблица увеличивается, появляются обновления строк, удаления и т.д. на.

По сути, теперь у нас есть список разделов и самых последних дат, и нам нужно выяснить оценки. Таким образом, мы должны присоединиться к этой таблице g1, которую мы только что получили в таблицу оценок, чтобы найти строку, которая содержит самую последнюю дату для каждого раздела. Идентификатор - единственный столбец, мы уверены, что он уникален (если мы не объединяем уникальный столбец или уникальный список столбцов, мы получим больше строк, и нам нужен ровно один), поэтому мы пытаемся найти этот идентификатор в зависимом подзапросе g2 ( это подзапрос, который ссылается на значения извне, в данном случае из gmax, который является псевдонимом для g1, объясненного ранее).

Как только у нас есть оценка для каждого section_id, остается только присоединить его к таблице разделов section_id, чтобы получить section_name вместо его значения id.

0 голосов
/ 26 мая 2011
SELECT grades.*,sections.* 
 FROM grades inner join sections on grades.sections_id = sections.id 
 where grades.user_id = '.$id.' 
 GROUP BY grades.section_id 
 ORDER BY grades.date DESC

Вы можете использовать это работает 100%

0 голосов
/ 26 мая 2011
SELECT sections.section_name, grades.grade

                    FROM 
                    grades, 
                    sections 

                    WHERE 
                    sections.id = grades.section_id

                    AND
                    grades.user_id = '.$id.'

                    ORDER BY grades.date DESC

                    LIMIT 1

попробуйте это?

0 голосов
/ 26 мая 2011

Если я правильно понимаю:

SELECT grades.*,sections.* 
  FROM grades INNER JOIN sections ON sections.id = grades.section_id 
  WHERE user_id=$id  ORDER BY grades.date DESC LIMIT 1
0 голосов
/ 26 мая 2011

Мне недавно пришлось сделать что-то похожее, но с T-SQL, поэтому вам придется изменить его самостоятельно, чтобы заставить его работать в MySQL (который я не установил здесь, поэтому я не могу проверить вас, ябоюсь).

Добавить в предложение WHERE:

AND grades.date = (SELECT TOP 1 date 
                     FROM grades 
                       WHERE date > GETDATE() 
                   ORDER BY ABS(CONVERT(FLOAT,GETDATE() - date)))

GETDATE() эквивалентно NOW(), TOP 1 похоже на LIMIT 1 и другие функции, хорошоЯ не знаю эквивалентов MySQL на моей голове!

0 голосов
/ 26 мая 2011

Если я правильно понял, вам нужна последняя оценка для каждого раздела.Это не может быть сделано просто с MySQL.

Вам понадобится оконная функция или генератор последовательности, ни один из которых не доступен в MySQL.Однако существует обходной путь с использованием переменных.См. Этот вопрос для аналогичного варианта использования:

Запрос MySQL: использование UNION и получение номера строки как части SELECT

Дополнительная справочная информация здесь:

SQL / mysql - выберите отдельный / УНИКАЛЬНЫЙ, но вернете все столбцы?

Вероятно, в конечном итоге вы выполните большой вложенный запрос, который будет выглядеть так:1016 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...