2

我了解 ANSI SQL 需要使用聚合函数选择非 GROUP BY 属性。

例如,下面在 ANSI SQL 中是无效的:

SELECT name, MAX(salary), dept 
FROM `employee_gb`
GROUP BY dept;

asname没有传递给任何聚合函数。

但是,MySQL 允许这样做。如果我们想让 MySQL 表现得像 ANSI SQL,我们需要按照这里的说明设置 sql 模式。但是当我尝试这样做时,它仍然没有给我任何错误:

SET GLOBAL sql_mode = 'ANSI';

SELECT name, MAX(salary), dept FROM employee_gb GROUP BY dept;

我想上面的查询应该给我错误。我在这里缺少什么?

以下是填充数据的查询:

CREATE TABLE `employee_gb`
(name varchar(50), salary float, dept varchar(50));

INSERT INTO `employee_gb` VALUES('a',1,'dept3'); 
INSERT INTO `employee_gb` VALUES('b',2,'dept4'); 
INSERT INTO `employee_gb` VALUES('c',3,'dept1'); 
INSERT INTO `employee_gb` VALUES('d',4,'dept2'); 
INSERT INTO `employee_gb` VALUES('e',5,'dept2'); 
INSERT INTO `employee_gb` VALUES('g',5,'dept2'); 
INSERT INTO `employee_gb` VALUES('f',6,'dept1'); 

这些是从 CLI 执行的一些屏幕截图:

在此处输入图像描述

在此处输入图像描述

4

4 回答 4

2

ONLY_FULL_GROUP_BY在 MySQL 5.7 中被添加到 sql 模式,通过比较5.6 文档5.7 文档ANSI可以看出。

我的猜测是您正在运行 MySQL 5.6 或更低版本。在这个版本中,如果你想要那个特定的行为,你需要ONLY_FULL_GROUP_BY单独设置,比如:

SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY';

DB Fiddle 上的演示- 一旦设置了正确的 sql 模式,查询错误:

'employee_gb.name' isn't in GROUP BY

旁注:重置整体通常不是一个好主意sql_mode,因为它会丢弃现有模式。您可以改为连接:

SET SESSION sql_mode = concat_ws(',', @@sql_mode, 'ONLY_FULL_GROUP_BY');
于 2020-06-21T20:44:39.227 回答
1

SQL 模式ANSIREAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, 和 (从 MySQL 5.7.5 开始) 的组合ONLY_FULL_GROUP_BY

因此,请检查您的 MySQL 版本。

于 2020-06-21T20:42:18.863 回答
1

设置全局选项不会更改当前会话的值。MySQL 会话在会话启动时复制全局变量的值,因此给定会话不受全局变量后续更改的影响(有一些例外情况,例如read_only)。

演示:

mysql> select @@sql_mode;
+------------------------+
| @@sql_mode             |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)

mysql> set global sql_mode = 'ANSI';
Query OK, 0 rows affected (0.00 sec)

mysql> select @@sql_mode;
+------------------------+
| @@sql_mode             |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)

mysql> select @@global.sql_mode;
+--------------------------------------------------------------------------------+
| @@global.sql_mode                                                              |
+--------------------------------------------------------------------------------+
| REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI |
+--------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select @@session.sql_mode;
+------------------------+
| @@session.sql_mode     |
+------------------------+
| NO_ENGINE_SUBSTITUTION |
+------------------------+
1 row in set (0.00 sec)

尝试以下操作来做你想做的事情:

mysql> SET SESSION sql_mode = 'ANSI';

这将改变当前会话的值。


另一种解决方案是在更改全局选项后重新连接,以便您开始一个新会话。这将重新读取全局值。

mysql> connect;
Connection id:    9
Current database: test

mysql> select @@session.sql_mode;
+--------------------------------------------------------------------------------+
| @@session.sql_mode                                                             |
+--------------------------------------------------------------------------------+
| REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ONLY_FULL_GROUP_BY,ANSI |
+--------------------------------------------------------------------------------+
1 row in set (0.00 sec)
于 2020-06-21T21:22:10.680 回答
0

只有完整的分组,不会解决您的问题,完全,完整的分组只会迫使您决定,当列不在 Group By 子句中时,您必须放弃您想要的数字。在以下查询中,您会看到

SELECT MAX(salary) maxsalary,dept FROM employee_gb GROUP BY dept

所有列都在 group by(dept) 中,或者具有像 MAX(salary) 这样的聚合函数。name 不在此选择中,因为数据库不会与行一起使用,因此您需要 alsp 定义要选择的名称,以获得完整的 GROUP By 查询。

我通过使用查询作为基础来选择正确的行,而不使用不允许选择正确名称的 GROUP BY,从而消除了这方面的必要性。

由于您没有指定,当两个人的薪水相同时会发生什么,您可以从这里开始

CREATE TABLE `employee_gb`
(name varchar(50), salary float, dept varchar(50));

INSERT INTO `employee_gb` VALUES('a',1,'dept3'); 
INSERT INTO `employee_gb` VALUES('b',2,'dept4'); 
INSERT INTO `employee_gb` VALUES('c',3,'dept1'); 
INSERT INTO `employee_gb` VALUES('d',4,'dept2'); 
INSERT INTO `employee_gb` VALUES('e',5,'dept2'); 
INSERT INTO `employee_gb` VALUES('g',5,'dept2'); 
INSERT INTO `employee_gb` VALUES('f',6,'dept1'); 
SELECT * FROM employee_gb WHERE (salary,dept) IN(SELECT MAX(salary),dept FROM employee_gb GROUP BY dept)
姓名 | 工资 | 部门
:--- | -----: | :----
一个 | 1 | 部门3
乙 | 2 | 部门 4
电子| 5 | 部门2
克 | 5 | 部门2
f | 6 | 部门 1
SELECT t1.* FROM employee_gb t1
INNER JOIN (SELECT MAX(salary) maxsalary,dept FROM employee_gb GROUP BY dept) t2
ON t1.salary = t2.maxsalary AND t1.dept = t2.dept
姓名 | 工资 | 部门
:--- | -----: | :----
一个 | 1 | 部门3
乙 | 2 | 部门 4
电子| 5 | 部门2
克 | 5 | 部门2
f | 6 | 部门 1

db<>在这里摆弄

于 2020-06-21T20:42:22.517 回答