在mysql中只设置了\u full \u group \u by sql模式来理解非标准groupby

envsm3lx  于 2021-07-24  发布在  Java
关注(0)|答案(4)|浏览(336)

我知道ansisql要求使用aggregate函数选择非groupby属性。
例如,以下内容在ansi sql中无效:

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

作为 name 未传递给任何聚合函数。
然而,mysql允许这样做。如果我们想让mysql像ansisql那样工作,我们需要按照这里的说明设置sql模式。但当我试着这么做的时候,还是没有给我任何错误:

SET GLOBAL sql_mode = 'ANSI';


我想上面的查询应该会给我错误。我错过了什么?
以下是填充数据的查询:

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执行的一些屏幕截图:

f5emj3cl

f5emj3cl1#

只有full groupby,不会解决您的问题,完全地,full groupby只强制您决定,当groupby子句中没有一列时,您必须放弃您要的数字。在下面的查询中,您将看到

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

所有列都在group by(dept)中,或者具有类似max(salary)的聚合函数。名称不在这个select中,因为数据库不与行连接,所以您需要alsp来定义要选择的名称,以便通过查询获得完整的组。
通过使用查询作为基础来选择正确的行,而不使用不允许选择正确名称的groupby,我消除了这样做的必要性。
因为你没有具体说明,如果两个人的薪水相同,你可以从这里开始

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)
name | salary | dept 
:--- | -----: | :----
a    |      1 | dept3
b    |      2 | dept4
e    |      5 | dept2
g    |      5 | dept2
f    |      6 | dept1
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
name | salary | dept 
:--- | -----: | :----
a    |      1 | dept3
b    |      2 | dept4
e    |      5 | dept2
g    |      5 | dept2
f    |      6 | dept1

db<>在这里摆弄

ttp71kqs

ttp71kqs2#

ONLY_FULL_GROUP_BY 已添加到sql模式 ANSI 在MySQL5.7中,通过比较5.6文档和5.7文档可以看出。
我猜您运行的是MySQL5.6或更低版本。在这个版本中,如果您想要特定的行为,您需要设置 ONLY_FULL_GROUP_BY 分开,比如:

SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY';

db fiddle上的demo-一旦设置了正确的sql模式,查询就会出错: 'employee_gb.name' isn't in GROUP BY 旁注:通常情况下,重置整个系统不是一个好主意 sql_mode ,因为它将放弃现有模式。您可以连接:

SET SESSION sql_mode = concat_ws(',', @@sql_mode, 'ONLY_FULL_GROUP_BY');
5kgi1eie

5kgi1eie3#

sql模式 ANSI 是对 REAL_AS_FLOAT , PIPES_AS_CONCAT , ANSI_QUOTES , IGNORE_SPACE ,和(从MySQL5.7.5开始) ONLY_FULL_GROUP_BY .
所以,检查你的mysql版本。

osh3o9ms

osh3o9ms4#

设置全局选项不会更改当前会话的值。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)

相关问题