mysql group_concat - PullRequest
       4

mysql group_concat

1 голос
/ 29 октября 2010

У меня есть две таблицы.

продукты

id  title      image_ids
---------------------
1   myproduct  1,2,3

images

id  title     file_name
-------------------------
1   myimage   myimage.jpg
2   myimage2  myimage2.jpg
3   myimage3  myimage3.jpg

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

Этот запрос не работает

   SELECT products.title,
          products.image_ids,
          GROUP_CONCAT(images.file_name)
     FROM products
LEFT JOIN images ON images.id IN (products.image_ids)
    WHERE products.id = 1
    GROUP BY products.id

Этот запрос:

   SELECT products.title,
          products.image_ids,
          GROUP_CONCAT(images.file_name)
     FROM products
LEFT JOIN images ON images.id IN (1,2,3)
    WHERE products.id = 1
    GROUP BY products.id

И дает желаемые результаты

title       image_ids  file_names
--------------------------------------------------------------
myproduct   1,2,3      myimage.jpg,myimage2.jpg,myimage3.jpg 

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

1 Ответ

2 голосов
/ 29 октября 2010

IN не работает для разделенных запятыми списков значений.

По сути, вы не сравниваете целые числа, вы сравниваете строки:

SELECT  1 IN (1, 2, 3) -- True
SELECT  1 IN ('1, 2, 3') -- False ('1' <> '1, 2, 3')

Вместо этого используйте FIND_IN_SET:

SELECT  products.title,products.image_ids, GROUP_CONCAT(images.file_name)
FROM    products
LEFT JOIN
        images
ON      FIND_IN_SET(images.id, products.image_ids)
WHERE   products.id = 1
GROUP BY
        products.id

Это, однако, не лучшее решение с точки зрения производительности, поскольку FIND_IN_SET не может быть sargable.Это потребует полного сканирования таблицы на images.

Если у вас есть разумное ограничение на количество значений в products.image_ids (скажем, не более 5 изображений на продукт), вы можете использоватьэтот запрос вместо:

SELECT  products.title,products.image_ids, GROUP_CONCAT(images.file_name)
FROM    (
        SELECT  1 AS n
        UNION ALL
        SELECT  2 AS n
        UNION ALL
        SELECT  3 AS n
        UNION ALL
        SELECT  4 AS n
        UNION ALL
        SELECT  5 AS n
        ) q
CROSS JOIN
        products
LEFT JOIN
        images
ON      SUBSTRING_INDEX(SUBSTRING_INDEX(image_ids, ',', n), ',', 1)
WHERE   products.id = 1
        AND SUBSTRING_INDEX(image_ids, ',', n) <> SUBSTRING_INDEX(image_ids, ',', n - 1)
GROUP BY
        products.id
...