MySQL GROUP BY 丢失的子查询中的 ORDER BY

MySQL ORDER BY from subquery lost by GROUP BY

我有一个 table x :

id lang externalid

1 nl 10

2 nl 11

3 fr 10

从这个 table 我想要特定语言和 externalid 的所有行,如果该语言不存在 externalid,我想要任何其他语言的行。

子查询排序table正确,但是当我添加group by时,子查询的排序丢失了。这适用于较旧的 mysql 版本,但不适用于 5.7。

(
 SELECT
  *
 FROM
  x
 ORDER BY FIELD(lang, "fr") DESC, id
)
 as y
group by externalid

我希望查询 return ID 为 2 和 3 的记录。因此,对于每个不同的外部 ID,如果可能,lang = 'fr',否则任何其他 lang。

我该如何解决这个问题?

您的子查询生成一个结果集(一个虚拟 table)并传递给您的外部查询。

所有 SQL 查询无一例外地以 unpredictable order 生成其结果,除非您在 ORDER BY 中完全指定顺序条款。

Unpredictable 就像 random, 除了更糟。随机意味着每次 运行 查询时您都会得到不同的顺序。 Unpredictable 意味着您每次都会得到相同的订单,直到您不这样做为止。

MySQL 通常忽略子查询中的 ORDER BY 子句(有一些例外,主要与子查询 LIMIT 子句有关)。将您的 ORDER BY 移至顶级查询。

编辑。您还滥用了 MySQL 对 GROUP BY 臭名昭著的非标准扩展。

你说的是给定 externalidland。因此无需按 externalid 分组;仅使用 where 子句。

ORDER BYLIMIT 相结合,您将获得所需的记录(即,如果存在这样的记录,则为所需的语言,否则为其他语言)。

select *
from mytable
where externalid = 10
order by lang = 'fr' desc
limit 1;

更新: 好的,根据您的评论,您希望每个 externalid 获得 "best" 条记录。在标准 SQL 中,您将为此使用 ROW_NUMBER。其他 DBMS 有进一步的解决方案,例如Oracle 的 KEEP FIRST 或 Postgre 的 DISTINCT ON。 MySQL 不支持其中任何一个。一种方法是用变量模拟 ROW_NUMBER。另一种方法是将上述查询用作每个 externalid 的子查询以查找最佳记录:

select *
from mytable
where id in
(
  select
    (
      select m.id
      from mytable m
      where m.externalid = e.externalid
      order by m.lang = 'fr' desc
      limit 1
    ) as best_id
  from (select distinct externalid from mytable) e
);