当 运行 `SELECT INNER JOIN WHERE t1.column=t2.column` 并且有多个匹配项时,您如何控制选择哪个匹配项?

How do you control which match is chosen when running a `SELECT INNER JOIN WHERE t1.column=t2.column` and there are multiple matches?

我有两个 MySQL 表:

产品

title    id    hidden   categories
Thing    10    N        12,14,
Stuff    23    N        12,
Object   41    Y        13,14

图片

filename     id    productid
aca8t.jpg    1     10
ev7ha.jpg    2     10
mscpk.jpg    3     10
asges.jpg    4     23
fcuhg.jpg    5     23
scvfe.jpg    6     41
vf6kl.jpg    7     41
fgszy.jpg    8     41

我使用如下 SELECT 语句构建产品标题和图片列表:

SELECT     t1.title,
           t1.id,
           t1.hidden,
           t1.categories,
           t2.image
FROM       products AS t1
INNER JOIN pimage   AS t2
WHERE      t1.categories LIKE '%$categoryId%'
AND        t1.id=t2.productid
AND        NOT t1.hidden='Y'
GROUP BY   id
ORDER BY   id ASC

在 运行 这个查询之后,我得到了给定类别中 non-hidden 产品的列表,以及它们的 ID 和一张图片。然而,图像的选择似乎是随机的。有时它是按字母顺序排列的,有时它是最低 ID,有时两者都不是。但是,当给定 productid 的文件名保持不变时,它总是相同的。

这是在一个小型网站上使用的,产品经理在该网站上上传产品及其配件的照片。第一张照片应用作缩略图并在类别页面上可见。但是,有时会选择随机配饰的照片作为缩略图,产品经理必须 re-upload 图片直到选择正确的图片。这个过程很繁琐。

如何修改 SQL 语句以便选择第一张照片(具有最低 images.id 的文件名)?

尝试使用相关子查询而不是 join/group by:

SELECT p.*,
       (SELECT i.image
        FROM pimage i
        WHERE p.id = i.productid 
        ORDER BY i.image ASC
        LIMIT 1
       ) as image
FROM  products p
WHERE p.categories LIKE '%$categoryId%' AND
      p.hidden <> 'Y'
ORDER BY p.id ASC

如果此语句在另一个关系数据库(MySQL/MariaDB 除外)上执行,它会抛出一条错误消息,并显示 "non-aggregates in SELECT list not included in GROUP BY".

行的消息

但是 GROUP BY 的 MySQL 特定扩展允许此查询在 MySQL 中执行,但正如您所注意到的,return 中的非聚合值SELECT 列表是 不确定的,MySQL 将 return 来自 一些 行的值。

正常模式是使用 MAX()MIN() 聚合函数到 "control",其值为 returned。

在您的情况下,这将适用于 return 最小 id 值,但在同一行上获取其他值更成问题。如果只需要return几列,可以在SELECT列表中使用相关子查询。

另一种方法是使用内联视图和连接操作。

  SELECT t1.title
       , t1.id
       , t1.hidden
       , t1.categories
       , t2.image
    FROM products t1
    JOIN ( SELECT n.productid
                , MIN(n.id) AS min_id
             FROM pimage n
            GROUP BY n.productid
         ) m
      ON m.productid = t1.id
    JOIN pimage t2
      ON t2.id = m.min_id
   WHERE t1.categories LIKE '%$categoryId%'
     AND t1.hidden='Y'
   GROUP BY t1.id
   ORDER BY t1.id ASC

当您需要从具有 "minimum" ID 的行中 return 额外的列时,此方法很有用。例如,您还需要在 SELECT 列表中包括:

       , t2.fee
       , t2.fi
       , t2.fo
       , t2.fum