H2 抱怨语法错误,MySQL 接受它 - 但是,错误的语法给出了正确的结果:列 ... 必须在 GROUP BY 列表中;

Posted

技术标签:

【中文标题】H2 抱怨语法错误,MySQL 接受它 - 但是,错误的语法给出了正确的结果:列 ... 必须在 GROUP BY 列表中;【英文标题】:H2 complains about the bad grammar, MySQL accepts it - However, bad syntax gives the right results: Column ... must be in the GROUP BY list; 【发布时间】:2020-08-11 14:08:24 【问题描述】:

注意:对问题进行了编辑以包含表格并显示预期的结果。

假设我们有一个生成的 SQL 表:

CREATE TABLE T1 (
  `a` INTEGER,
  `b` DATETIME,
  `c` VARCHAR(5)
);

INSERT INTO T1
  (`a`, `b`, `c`)
VALUES
  ('5678', '2008-01-01 12:00', '12.34'),
  ('5678', '2008-01-01 12:01', NULL),
  ('5678', '2008-01-01 12:02', NULL),
  ('5678', '2008-01-01 12:03', '23.45'),
  ('5678', '2008-01-01 12:04', NULL);

我需要执行的是

SELECT * FROM(
  SELECT a, b, c  from T1
)AS Q GROUP BY c ORDER BY a, b;

这给出了:

5678    2008-01-01 12:00:00     12.34
5678    2008-01-01 12:01:00     NULL
5678    2008-01-01 12:03:00     23.45

H2 建议(并接受)的是

SELECT * FROM(
  SELECT a, b, c  from T1
)AS Q GROUP BY a,b,c ORDER BY a, b, c;

这给了

5678    2008-01-01 12:00:00     12.34
5678    2008-01-01 12:01:00     NULL
5678    2008-01-01 12:02:00     NULL
5678    2008-01-01 12:03:00     23.45
5678    2008-01-01 12:04:00     NULL

根据您的一些建议,这些是查询和结果。

建议一:

SELECT  max(a) as a, max(b) as b, c
FROM (
  SELECT a, b, c  from T1
) AS Q 
GROUP BY c 
ORDER BY a, b;

给予

5678    2008-01-01 12:00:00     12.34
5678    2008-01-01 12:03:00     23.45
5678    2008-01-01 12:04:00     NULL

建议 2:

SELECT * 
FROM (
  SELECT a, b, c from T1
) AS Q 
GROUP BY c, a, b 
ORDER BY a, b;

给予

5678    2008-01-01 12:00:00     12.34
5678    2008-01-01 12:01:00     NULL
5678    2008-01-01 12:02:00     NULL
5678    2008-01-01 12:03:00     23.45
5678    2008-01-01 12:04:00     NULL

========================================

我需要获取第一个查询执行的结果。

在获得预期结果的同时,我应该如何正确更改语法以适应 H2 需求?

【问题讨论】:

这是 mysql 中的不幸行为。显然,第一个查询是胡言乱语。如需进一步帮助,请参阅:Why should I provide an MCRE for what seems to me to be a very simple SQL query? 为什么你认为第一个查询的结果是正确的?在这种情况下,Mysql 只返回列 c 的 any 值。 对所有人:第一个查询给出了想要的结果。 【参考方案1】:

现在,对于修改后的问题。根据样本数据,在H2中你可以这样做:

select t1.*
from t1
join (
  select c, min(b) as min_b from t1 group by c
) x on t1.c is not distinct from x.c and t1.b = x.min_b
order by t1.b;

结果:

A     B                      C     
----  ---------------------  ------
5678  2008-01-01 12:00:00.0  12.34 
5678  2008-01-01 12:01:00.0  <null>
5678  2008-01-01 12:03:00.0  23.45 

重现案例的示例数据脚本为:

create table t1 (
  a integer,
  b datetime,
  c varchar(5)
);

insert into t1 (a, b, c) values
  ('5678', timestamp '2008-01-01 12:00:00', '12.34'),
  ('5678', timestamp '2008-01-01 12:01:00', null),
  ('5678', timestamp '2008-01-01 12:02:00', null),
  ('5678', timestamp '2008-01-01 12:03:00', '23.45'),
  ('5678', timestamp '2008-01-01 12:04:00', null);

【讨论】:

【参考方案2】:

H2 行为正确。旧版本的 MySQL 允许执行查询,即使根据 ANSI/ISO SQL 和几乎所有其他 SQL 实现(SQLite 除外)它是无效的。

我在Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause写了一个例子来解释它

您必须更正查询才能使用 H2。

规则是选择列表的每一列必须要么在聚合函数内,要么在 GROUP BY 子句中命名。

你可以这样解决:

SELECT MAX(a) AS a, MAX(b) AS b, c FROM(
  SELECT a, b, c  from T1
)AS Q GROUP BY c ORDER BY a, b;

这满足规则,因为ab 在聚合函数中,而cGROUP BY 中。

MySQL 5.7 及更高版本默认行为正确,按语义强制分组。

【讨论】:

给出不同的结果【参考方案3】:

您可能正在使用用于接受此类查询的 MySQL 5.7.5 或更早版本。如果您使用的是较新的 MySQL,您可能启用了旧的/格式错误的语法。

查询:

SELECT * 
FROM (
  SELECT a, b, c  from T1
) AS Q 
GROUP BY c 
ORDER BY a, b;

格式错误。为什么?因为未包含在GROUP BY 子句中的列(在这种情况下为ab)必须在选择列表中聚合。您的选择列表包括所有列,并且自您使用 * 以来没有汇总。

这个格式错误的 MySQL 查询不符合 SQL 标准,并且会为非聚合列生成随机值。 这是您的应用程序的实际错误

然而,H2 理所当然地拒绝它并要求您修复它。您可以执行任何有效的替代方案,例如:

SELECT c, max(a) as a, max(b) as b
FROM (
  SELECT a, b, c  from T1
) AS Q 
GROUP BY c 
ORDER BY a, b;

或者也许:

SELECT * 
FROM (
  SELECT a, b, c from T1
) AS Q 
GROUP BY c, a, b 
ORDER BY a, b;

【讨论】:

试过,但结果不同 @DamirOlejar “不同”可能是指“正确”。 不,我的意思是,不需要。 :) 语法是正确的,但结果不是我需要的。我需要错误语法产生的相同结果。 @DamirOlejar 我知道...这是个笑话 ;-) 我认为您可能需要包含一些示例数据和预期结果,以帮助您根据需要重写最佳查询。此答案仅解决查询的格式错误的语法。【参考方案4】:

如果只需要查询 H2,可以使用非标准 PostgreSQL 风格的DISTINCT ON 子句代替分组查询:

SELECT DISTINCT ON(C) A, B, C FROM T1 ORDER BY A, B;

AB 值将根据 ORDER BY 子句进行选择。

【讨论】:

有趣,会尝试。 您需要最新版本的 H2,顺便说一句,不同的过时版本不支持它。此类查询也适用于 PostgreSQL 及其分支,但不适用于其他 DBMS。 问题是我有一个非常复杂的查询,从 MySQL 到 PostgreSQL 模式会太多。但是,这个解决方案是我使用 GROUP BY 的原因

以上是关于H2 抱怨语法错误,MySQL 接受它 - 但是,错误的语法给出了正确的结果:列 ... 必须在 GROUP BY 列表中;的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL模式下的h2数据库不接受PostgreSQL SQL语法

错误的 SQL 语法...找不到列“COUNT(status)”

连接到 Mysql AWS RDS 实例时工作台错误 10060

使用MYSQL时,Grails条件查询失败,语法错误

H2 SQL 语句中是不是有语法错误?

Hibernate 不在内存数据库中使用 H2 创建表