Хобрук: Ваш путь к мастерству в программировании

Комбинация SUM(), GROUP_BY() и LEFT_JOIN() возвращает неверные результаты: как исправить?

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

Таблица выглядит примерно так:

+------------------------------------------+
| id | entity_id | minutes | person | date |
+------------------------------------------+

Как должен выглядеть результат должен:

+----------------------------+
| year | month | day | hours |
| 2008 | 12    | 1   | 30    |
| 2008 | 12    | 2   | 40    |
| 2008 | 12    | 3   | 23    |
+----------------------------+

Вместо этого hours часто намного больше из-за возвращаемых строк, вызванных left join.

Проблема в том, что мне нужно запросить эту таблицу на основе тегов, связанных с соответствующими объектами. Когда я соединяю две таблицы (tag_entity, которая предоставляет ссылку, и tags, которая предоставляет фактические имена тегов), моя SUM() больше не работает, так как возвращается слишком много результатов.

Запрос:

select 
    date_format(from_unixtime(date), '%Y-%m-%d') as myDate,
    ROUND(SUM(time) / 60,1) as hours

from time h

left join tag_entity te on te.entity_id = h.entity_id
left join tags t on t.tag_id = te.tag_id

where (t.tag_name NOT IN ('foo', 'bar', 'baz') OR t.tag_name IS NULL) 

group by
    myDate

order by
    hours DESC, myDate ASC

Как я могу это исправить?

РЕДАКТИРОВАТЬ:

Вот схемы для tag и tag_entity:

Tag:

+----------+-------------+
| Field    | Type        |
+----------+-------------+
| tag_id   | int(11)     |
| tag_name | varchar(50) |
+----------+-------------+

И tag_entity:

+-----------+---------+
| Field     | Type    |
+-----------+---------+
| id        | int(11) |
| tag_id    | int(11) |
| entity_id | int(11) |
+-----------+---------+
18.03.2011

  • Может быть, я еще не выпил достаточно кофе, но у меня возникли проблемы с выводом вашей схемы. Не могли бы вы опубликовать соответствующие части схем для тегов и tag_entity? Кроме того, в какой таблице определяется дата и время? 18.03.2011
  • @Андрей спасибо за ответ. Добавил схемы. date и time находятся в моей таблице time. 18.03.2011
  • Вы выбираете from t и делаете left join tags t - синтаксическая ошибка. Вы забыли указать имя основной таблицы? 18.03.2011
  • @Марк ой. Выложенный запрос несколько подкорректирован и в исходном такой проблемы не возникает. Будет исправлено в этом примере. 18.03.2011
  • Вам нужны объекты без одного из тегов («foo», «bar», «baz») или вам нужны объекты, содержащие тег, отличный от («foo», «bar», «baz»)? Если объект 1 имеет тег «foo» и тег «me», должен ли он быть включен или нет? 18.03.2011
  • Поскольку столбец в таблице time равен hours, что именно суммирует SUM(time)/60? Деление на 60 предполагает, что что-то записывается в минутах. 18.03.2011
  • @ Джонатан, правильно, hours здесь просто мета. Изменил его на minutes, чтобы прояснить это. 18.03.2011
  • @jswolf Я действительно хочу смоделировать оба случая. Приведенный выше пример должен возвращать только те строки в таблице time, которые не связаны с одним из этих тегов. 18.03.2011

Ответы:


1

GROUP BY группирует результаты, а не строки таблицы по отдельности.

На основании вашего комментария возвращать только те строки в расписании, которые не связаны ни с одним из этих тегов:

SELECT 
    date_format(from_unixtime(date), '%Y-%m-%d') as myDate,
    ROUND(SUM(time) / 60,1) as hours
FROM `time` h
  LEFT JOIN (
    SELECT DISTINCT te.entity_id
    FROM tag_entity te
      LEFT JOIN tags t on t.tag_id = te.tag_id
    WHERE te.entity_id IS NOT NULL AND t.tag_name IN ('foo', 'bar', 'baz')
  ) g ON h.entity_id = g.entity_id
WHERE g.entity_id IS NULL
group by
    myDate

order by
    hours DESC, myDate ASC
18.03.2011
  • Вау, ты действительно прибил это. Большое спасибо, вы просто сделали мои выходные. 18.03.2011

  • 2

    Вероятно, вы хотите что-то вроде этого:

    select 
        date_format(from_unixtime(date), '%Y-%m-%d') as myDate,
        ROUND(SUM(time) / 60,1) as hours
    
    from time h
    

    <забастовка> left join tag_entity te on te.entity_id = h.entity_id

    where NOT EXISTS(select te.entity_id
    
                     from tag_entity te
    
                     join tags t on t.tag_id = te.tag_id
    
                     where te.tag_entity = h.entity_id  AND t.tag_name IN ('foo', 'bar', 'baz')) 
    
    group by
        myDate
    
    order by
        hours DESC, myDate ASC
    
    18.03.2011

    3
  • Кроме изменения формата даты в один столбец, это ничего не решает. Однако, чтобы упростить запрос, я изменил его, чтобы он возвращал только один столбец даты. 18.03.2011
  • Вы проверили это? Это не просто изменение формата даты. Проблема с вашим запросом заключается в том, что вы группируете по месяцам всех лет и дням всех месяцев и лет, скажем, сумме всех январей всех лет. Это не имеет ничего общего с левым соединением. Кроме того, разве вы не имеете в виду AND t.tag_name IS NOT NULL? 18.03.2011
  • да, я проверил это, безрезультатно, к сожалению. Предложение GROUP BY не должно работать так, как вы описываете: оно объединяет групповые аргументы. Ваш пример приводит к точно такому же результату. 18.03.2011
  • Новые материалы

    Прогресс в технологии Трансформеров часть 3
    Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

    Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
    Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

    Приключения в Javascript, часть 1
    Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

    Понимание дженериков в TypeScript: подробное руководство
    Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

    Учебные заметки JavaScript Object Oriented Labs
    Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

    Разбор строк запроса в vue.js
    Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

    Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
    «Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..