CONCAT_WS 系统之间的行为差异
Difference in behavior on CONCAT_WS between systems
所以,这是一个简单的情况,但我想了解导致此问题的原因。我有以下代码(例如修改):
SELECT `Transactions`.*, CONCAT_WS(" ", `People`.`first_name`, `People`.`last_name`) AS full_name ...
在我的本地机器上我有:
- Windows10
- 阿帕奇 2.4.25
- PHP 7.4.11
- MySQL 5.7.25
使用该组合,以下代码可以正常工作。
在我的远程服务器上:
- Ubuntu 20.04.1 LTS
- 阿帕奇 2.4.41
- PHP7.4.3
- MySQL 8.0.19
所以,我有一个部分使用数据 table 并且数据 table 使用服务器端处理来获取信息。在我的本地它正确显示信息,但在我的远程服务器上我总是得到一个空数组。所以我尝试在我的远程服务器上执行相同的 SQL 命令,但我得到了这个错误:
#1054 - Unknown column ' ' in 'field list'
我的 SQL 格式正确所以我认为问题可能与 CONCAT_WS
函数有关。
所以我决定修改为:
SELECT `Transactions`.*, CONCAT_WS(' ', `People`.`first_name`, `People`.`last_name`) AS full_name ...
我基本上将 CONCAT_WS(" ",
更改为 CONCAT_WS(' ',
,并且代码按预期运行。
我不确定这是否会以某种方式影响,但这是 MySQL 对 CONCAT_WS
或其他使用要求的更改吗?
如果我在别处用单引号可以吗?
我建议你 运行 在两个系统上都这样做:
SELECT @@sql_mode;
您会发现在您的 8.0 服务器上,sql 模式包括模式 ANSI
或 ANSI_QUOTES
。
解释:
双引号在 MySQL 中有不同的含义,具体取决于哪个 sql 模式有效。
默认情况下,双引号与单引号相同:它们分隔字符串文字。
如果 sql 模式是 ANSI
或 ANSI_QUOTES
,则双引号分隔标识符,作用类似于反引号。
因此,相同的代码在不同的 MySQL 实例中可能表现不同。这与 5.7 和 8.0 之间的差异无关,因为 sql 模式在这两个版本上的行为相同。默认情况下,这两个版本都不启用 ANSI
或 ANSI_QUOTES
模式,因此您或其他人必须在您的 8.0 服务器上启用该模式。
这就是为什么在这个表达式中:
CONCAT_WS(" ", ...)
第一个参数 " "
在一个服务器上被视为字符串文字,在另一台服务器上被视为名称为
的列(这是合法的 SQL, 即使它很奇怪).
最安全的做法是始终使用单引号来分隔字符串文字,并始终使用反引号来分隔标识符。
永远不要在 MySQL 中对任何一种情况使用双引号,因为如果有人更改 sql 模式,您在 SQL 查询中使用双引号的代码将会中断。
所以,这是一个简单的情况,但我想了解导致此问题的原因。我有以下代码(例如修改):
SELECT `Transactions`.*, CONCAT_WS(" ", `People`.`first_name`, `People`.`last_name`) AS full_name ...
在我的本地机器上我有:
- Windows10
- 阿帕奇 2.4.25
- PHP 7.4.11
- MySQL 5.7.25
使用该组合,以下代码可以正常工作。
在我的远程服务器上:
- Ubuntu 20.04.1 LTS
- 阿帕奇 2.4.41
- PHP7.4.3
- MySQL 8.0.19
所以,我有一个部分使用数据 table 并且数据 table 使用服务器端处理来获取信息。在我的本地它正确显示信息,但在我的远程服务器上我总是得到一个空数组。所以我尝试在我的远程服务器上执行相同的 SQL 命令,但我得到了这个错误:
#1054 - Unknown column ' ' in 'field list'
我的 SQL 格式正确所以我认为问题可能与 CONCAT_WS
函数有关。
所以我决定修改为:
SELECT `Transactions`.*, CONCAT_WS(' ', `People`.`first_name`, `People`.`last_name`) AS full_name ...
我基本上将 CONCAT_WS(" ",
更改为 CONCAT_WS(' ',
,并且代码按预期运行。
我不确定这是否会以某种方式影响,但这是 MySQL 对 CONCAT_WS
或其他使用要求的更改吗?
如果我在别处用单引号可以吗?
我建议你 运行 在两个系统上都这样做:
SELECT @@sql_mode;
您会发现在您的 8.0 服务器上,sql 模式包括模式 ANSI
或 ANSI_QUOTES
。
解释:
双引号在 MySQL 中有不同的含义,具体取决于哪个 sql 模式有效。
默认情况下,双引号与单引号相同:它们分隔字符串文字。
如果 sql 模式是 ANSI
或 ANSI_QUOTES
,则双引号分隔标识符,作用类似于反引号。
因此,相同的代码在不同的 MySQL 实例中可能表现不同。这与 5.7 和 8.0 之间的差异无关,因为 sql 模式在这两个版本上的行为相同。默认情况下,这两个版本都不启用 ANSI
或 ANSI_QUOTES
模式,因此您或其他人必须在您的 8.0 服务器上启用该模式。
这就是为什么在这个表达式中:
CONCAT_WS(" ", ...)
第一个参数 " "
在一个服务器上被视为字符串文字,在另一台服务器上被视为名称为
的列(这是合法的 SQL, 即使它很奇怪).
最安全的做法是始终使用单引号来分隔字符串文字,并始终使用反引号来分隔标识符。
永远不要在 MySQL 中对任何一种情况使用双引号,因为如果有人更改 sql 模式,您在 SQL 查询中使用双引号的代码将会中断。