mysql group_concat

时间:2010-10-28 21:19:14

标签: sql mysql aggregate-functions

我有两张桌子。

产品

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

图片

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 个答案:

答案 0 :(得分:2)

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不可攻击,因此这不是性能方面的最佳解决方案。它需要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