Нужна помощь с подсчетом подзапросов MySQL - PullRequest
3 голосов
/ 19 марта 2010

Я сталкиваюсь с моими собственными ограничениями навыков работы с MySQL, поэтому я надеюсь, что некоторые гуру SQL могут помочь с этим.Ситуация выглядит следующим образом:

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

  • Изображение
  • Tag
  • Tag_map (отображает изображения в теги)

У меня есть запрос SQL, который вычисляет связанные теги на основе идентификатора тега.Запрос в основном проверяет, какие другие теги использовались для изображений для изображений, использующих этот тег.Пример:

Изображение1, помеченное как «Медведь»
Изображение2, помеченное как «Медведь» и «Канада»

Если я брошу «Медведь» (или его идентификатор тега)) при запросе он вернет "Канада".Это отлично работает.Вот запрос:

SELECT tag.name, tag.id, COUNT(tag_map.id) as cnt
FROM tag_map,tag
WHERE tag_map.tag_id = tag.id AND tag.id != '185' AND tag_map.image_id IN

    (SELECT tag_map.image_id FROM tag_map INNER JOIN tag ON tag_map.tag_id = tag.id WHERE tag.id = '185')

GROUP BY tag_map.id LIMIT 0,100

Часть, с которой я застрял - это количество.Для каждого возвращенного связанного тега я хочу знать, сколько изображений в этом теге.В настоящее время он всегда возвращает 1, даже если есть, например, 3. Я попытался сосчитать разные столбцы, которые все приводят к одному и тому же результату, поэтому я думаю, что в моем мышлении есть изъян.

Ответы [ 2 ]

2 голосов
/ 19 марта 2010

Ваш код работает неправильно, потому что вы выбираете только изображения, "связанные с выбранным тегом", но не изображения, "связанные с тегами, связанными с изображением, связанным с выбранным тегом" (надеюсь, я использовал правильную глубину рекурсии :)).

Вы можете сделать это с помощью подвыборов:

SELECT tag.id, tag.name, COUNT(DISTINCT tag_map.image_id) as cnt
  FROM tag_map, tag
 WHERE tag_map.tag_id = tag.id
   AND tag.id != 185
   AND tag_map.tag_id IN (
     SELECT sub1.tag_id FROM tag_map AS sub1 WHERE sub1.image_id IN (
       SELECT sub2.image_id FROM tag_map AS sub2 WHERE sub2.tag_id = 185
     )
   )
GROUP BY tag.id, tag.name;
1 голос
/ 19 марта 2010

Пища для размышлений

  • Я заметил, что вы используете id в своей таблице тегов и изображений и tablename_id в своей таблице tag_map. У каждого своя собственная связь, но я обнаружил, что намного проще, если идентификатор везде одинаков. Я бы переименовал идентификаторы в tag & image в tag_id & image_id соответственно.
  • Кажется, ваши идентификаторы - это строки символов. Я позволил себе использовать целые числа в примерах.

В следующем примере используется SQL Server. Не должно быть трудно настроить SQL-оператор для MySQL.

Данные испытаний

DECLARE @tag TABLE (id INTEGER, tag VARCHAR(32))
DECLARE @image TABLE (id INTEGER, image VARCHAR(32))
DECLARE @tag_map TABLE (image_id INTEGER, tag_id INTEGER)

INSERT INTO @tag
SELECT 185, 'Bear' 
UNION ALL SELECT 186, 'Canada'

INSERT INTO @image
SELECT 1, 'image1'
UNION ALL SELECT 2, 'image2'

INSERT INTO @tag_map
SELECT 1, 185
UNION ALL SELECT 2, 185
UNION ALL SELECT 2, 186

Оператор SQL

SELECT  t.tag
        , t.id
        , cnt = (SELECT COUNT(*) FROM @tag_map WHERE tag_id = t.id)
FROM    @tag_map m
        INNER JOIN @tag t ON t.id = m.tag_id
        INNER JOIN (
          SELECT  m.image_id
          FROM    @tag_map m
          WHERE   m.tag_id = 185
        ) i ON i.image_id = m.image_id
WHERE   t.id <> 185
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...