何时在 MySQL 中使用单引号、双引号和反引号

Posted

技术标签:

【中文标题】何时在 MySQL 中使用单引号、双引号和反引号【英文标题】:When to use single quotes, double quotes, and backticks in MySQL 【发布时间】:2021-09-05 07:32:05 【问题描述】:

我正在尝试学习编写查询的最佳方法。我也明白保持一致的重要性。到现在为止,我随意使用了单引号、双引号和反引号,没有任何真正的想法。

例子:

$query = 'INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)';

另外,在上面的例子中,考虑tablecol1val1等可能是变量。

这个的标准是什么?你是做什么的?

我已经在这里阅读了大约 20 分钟的类似问题的答案,但这个问题似乎没有明确的答案。

【问题讨论】:

请注意,这是一个非常特定于 mysql 的问题。一般的 SQL(即 ISO/ANSI SQL)有一组不同的引号:双引号用于分隔标识符,例如"tablename",单引号用于文字,例如'this is a some text'。标准 SQL 中从不使用反引号。 (如果您需要在标识符中包含双引号,请输入两次"odd""tablename"。同样,在文字中使用双单引号,例如'Conan O''Brien'。) 【参考方案1】:

简单来说:

引号(单引号和双引号)用于字符串周围。

反引号用于表和列标识符周围。

同时实现单引号和双引号:

~如果我们想实现这个,

试试这个,

SELECT "They've found this tutorial to be helpful"

~想要实现这个:

试试这个,

SELECT 'They\'ve responded, "We found this tutorial helpful"'

完整说明:

:

【讨论】:

【参考方案2】:

有时不使用引号很有用...因为这可以突出生成查询的代码中的问题...例如:

其中 x 和 y 应始终为整数...

SELECT * FROM table WHERE x= AND y=0

是 SQL 语法错误吗……有点懒,但很有用……

【讨论】:

【参考方案3】:

反引号用于表和列标识符,但仅在标识符为 MySQL reserved keyword 或标识符包含空白字符或超出有限集合的字符时才需要(见下文) 通常建议避免尽可能使用保留关键字作为列或表标识符,避免引用问题。

单引号应用于字符串值,如VALUES() 列表中的值。 MySQL 也支持字符串值的双引号,但单引号被其他 RDBMS 更广泛地接受,因此使用单引号而不是双引号是一个好习惯。

MySQL 还期望 DATEDATETIME 文字值被单引号作为字符串,如 '2001-01-01 00:00:00'。请参阅 the Date and Time Literals 文档了解更多详细信息,尤其是在日期字符串中使用连字符 - 作为段分隔符的替代方法。

因此,使用您的示例,我将双引号 php 字符串并在值 'val1', 'val2' 上使用单引号。 NULL 是 MySQL 关键字和特殊(非)值,因此不加引号。

这些表或列标识符都不是保留字或使用需要引用的字符,但我还是用反引号引用了它们(稍后会详细介绍...)。

不应引用 RDBMS 的原生函数(例如,MySQL 中的 NOW()),尽管它们的参数遵循已提到的相同字符串或标识符引用规则。

反引号 (`)
表列────────┬──────┬──┬──┬──┬────┬──┬────┬──┬────┬──┬ ────────┐
                      ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `updated`)
                       值(NULL,'val1','val2','2001-01-01',NOW())“;
                               ↑↑↑↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑↑↑↑↑
不带引号的关键字─────┴┴┴┘ │ │ │ │ │ │ │││││
单引号 (') 字符串────────────┴────┴──┴────┘ │ │ │││││
单引号 (') 日期──────────────────────────┴──────────┘ ││││ │
不带引号的函数────────────────────────────────────────┴┴┴┴┘

变量插值

变量的引用模式不会改变,但如果您打算直接在字符串中插入变量,则必须在 PHP 中使用双引号。只需确保您已正确转义变量以在 SQL 中使用。 (It is recommended to use an API supporting prepared statements instead, as protection against SQL injection)。

// 与一些变量替换相同
// 这里,变量表名 $table 用反引号括起来,而变量
// 在 VALUES 列表中是单引号的
$query = "INSERT INTO `$table` (`id`, `col1`, `col2`, `date`) VALUES (NULL, '$val1', '$val2', '$date')";

准备好的陈述

使用准备好的语句时,请查阅文档以确定是否必须引用语句的占位符。 PHP、PDO 和 MySQLi 中最流行的 API 需要 unquoted 占位符,其他语言中的大多数准备好的语句 API 也是如此:

// PDO example with named parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)";

// MySQLi example with ? parameters, unquoted
$query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

在标识符中需要反引号的字符:

According to MySQL documentation,您不需要使用以下字符集引用(反引号)标识符:

ASCII:[0-9,a-z,A-Z$_](基本拉丁字母、数字 0-9、美元、下划线)

您可以使用超出该设置的字符作为表或列标识符,例如包括空格,但是您必须引用(反引号)它们。

此外,虽然数字是标识符的有效字符,但标识符不能仅由数字组成。如果是,则必须用反引号括起来。

【讨论】:

"但单引号被其他 RDBMS 更广泛地接受" - SQL 标准定义(并且要求)对字符串文字使用单引号 这不是真的:"MySQL 还期望 DATE 和 DATETIME 文字值作为字符串单引号,例如 '2001-01-01 00:00:00'" @evilReiko MySQL 文档似乎没有清楚地解决别名引用问题。它将接受别名的单引号、双引号或反引号,但这可能会受到不同 ANSI SQL 模式的影响。我不确定 SQL 规范对别名引号的要求——个人偏好:为了保持一致,我引用它们与列标识符相同——也就是说,如果需要,我要么反引号,要么不加引号。我不在别名上使用单引号或双引号。 @GuneyOzsan 是的,非常脆弱。永远不要使用变量作为表名,除非它已根据可接受的表名列表进行验证 - 创建一个允许的名称数组并检查变量是否与列表中的某些内容匹配以使其安全使用。否则,您无法安全地转义表名变量以供使用。 Michael 现在全部整理好了,谢谢。我是否建议编辑图表以添加绑定变量。这绝对是华丽的,如果另一个可怜的灵魂来检查:whatever,那就更可爱了。 ATB 史蒂夫【参考方案4】:

在 MySQL 中,这些符号用于分隔查询 `"'()

    "' 用于封装类似字符串的值 "26-01-2014 00:00:00"'26-01-2014 00:00:00' 。这些符号仅适用于字符串,不适用于 nowsummax 等聚合函数。

    ` 用于封闭表或列名,例如select `column_name` from `table_name` where id='2'

    () 仅包含查询的一部分,例如select `column_name` from `table_name` where (id='2' and gender='male') or name='rakesh'.

【讨论】:

【参考方案5】:

这里有很多有用的答案,通常总结为两点。

    BACKTICKS(`) 用于标识符名称周围。 单引号(') 用于值周围。

正如@MichaelBerkowski所说的那样

反引号用于表和列标识符,但 仅当标识符是 MySQL 保留关键字时才需要,或 当标识符包含空白字符或字符时 超出有限的集合(见下文) 通常建议避免 尽可能使用保留关键字作为列或表标识符, 避免引用问题。

在某些情况下,标识符既不能是保留关键字,也不能包含空格超出限制集的字符,但必须使用反引号在他们周围。

示例

123E10 是一个有效的标识符名称,但也是一个有效的 INTEGER 文字。

[不详细说明如何获得这样的标识符名称],假设我想创建一个名为 123456e6 的临时表。

反引号没有错误。

DB [XXX]> create temporary table `123456e6` (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

不使用反引号时出错。

DB [XXX]> create temporary table 123451e6 (`id` char (8));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '123451e6 (`id` char (8))' at line 1

但是,123451a6 是一个非常好的标识符名称(没有反引号)。

DB [XXX]> create temporary table 123451a6 (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

这完全是因为1234156e6也是一个指数。

【讨论】:

【参考方案6】:

SQL 服务器和 MySQL、PostgreySQL、Oracle 不理解双引号 (")。因此您的查询应该没有双引号 ("),并且应该只使用单引号 (')。

Back-trip(`) 在 SQL 中是可选的,用于表名、数据库名和列名。

如果您尝试在后端编写查询以调用 MySQL,那么您可以使用双引号 (") 或单引号 (') 将查询分配给如下变量:

let query = "select id, name from accounts";
//Or
let query = 'select id, name from accounts';

如果您的查询中有where 语句和/或尝试insert 一个值和/或一个字符串值的update,请对这些值使用单引号('),例如:

let querySelect = "select id, name from accounts where name = 'John'";
let queryUpdate = "update accounts set name = 'John' where id = 8";
let queryInsert = "insert into accounts(name) values('John')";

//Please not that double quotes are only to be used in assigning string to our variable not in the query
//All these below will generate error

let querySelect = 'select id, name from accounts where name = "John"';
let queryUpdate = 'update accounts set name = "John" where id = 8';
let queryInsert = 'insert into accounts(name) values("John")';

//As MySQL or any SQL doesn't understand double quotes("), these all will generate error.

如果您不想在使用双引号(“)和单引号(')时避免这种混乱,建议坚持使用单引号('),这将包括反斜杠(),如:

let query = 'select is, name from accounts where name = \'John\'';

当我们必须动态分配一些值并执行一些字符串连接时,就会出现双引号(“)或单引号(')的问题,例如:

let query = "select id, name from accounts where name = " + fName + " " + lName;
//This will generate error as it must be like name = 'John Smith' for SQL
//However our statement made it like name = John Smith

//In order to resolve such errors use
let query = "select id, name from accounts where name = '" + fName + " " + lName + "'";

//Or using backslash(\)
let query = 'select id, name from accounts where name = \'' + fName + ' ' + lName + '\'';

如果需要进一步的许可,请关注quotes in javascript

【讨论】:

【参考方案7】:

MySQL 中有两种类型的引号:

    ' 用于包含字符串文字 ` 用于封装标识符,例如表名和列名

然后是",这是一个特例。根据 MySQL 服务器的 sql_mode:

    默认情况下 " 字符可用于包含字符串文字,就像 'ANSI_QUOTES 模式下," 字符可用于包含标识符,就像`

以下查询将根据 SQL 模式产生不同的结果(或错误):

SELECT "column" FROM table WHERE foo = "bar"

ANSI_QUOTES 已禁用

查询将选择字符串文字"column",其中列foo等于字符串"bar"

ANSI_QUOTES 已启用

查询将选择列column,其中列foo 等于列bar

什么时候用什么

我建议您避免使用",以便您的代码独立于 SQL 模式 始终引用标识符,因为这是一种很好的做法(关于 SO 的很多问题都在讨论这个问题)

【讨论】:

或者,在 ANSI_QUOTES 模式下运行您的 MySQL 以使您的 SQL 技能集更具可移植性,并使用 ' 用于字符串," 用于标识符并且不要使用反引号。遵守标准总是好的 关于如何在会话级别启用ANSI_QUOTES 的其他人:SET SESSION sql_mode = 'ANSI_QUOTES'; or SET SESSION sql_mode = 'ANSI';。然后您可以SELECT @@SESSION.sql_mode; 来检查该值。如果要恢复到默认值,MySQL 5.7 的默认值为:SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';【参考方案8】:

除了所有(解释清楚的)答案之外,没有提到以下内容,我经常访问此问答。

简而言之; MySQL 认为您想对自己的表/列进行数学运算,并将连字符(例如“电子邮件”)解释为 e 减号 mail


免责声明:因此,我想我会将其添加为“仅供参考”类型的答案,以供那些完全不熟悉使用数据库并且可能不理解已经描述的技术术语的人使用。 p>

【讨论】:

【参考方案9】:

如果表列和值是变量,那么有两种方法:

用双引号"" 完整查询:

$query = "INSERT INTO $table_name (id, $col1, $col2)
                 VALUES (NULL, '$val1', '$val2')";

或者

 $query = "INSERT INTO ".$table_name." (id, ".$col1.", ".$col2.")
               VALUES (NULL, '".$val1."', '".$val2."')";

带单引号'':

$query = 'INSERT INTO '.$table_name.' (id, '.$col1.', '.$col2.')
             VALUES (NULL, '.$val1.', '.$val2.')';

当列/值名称类似于 MySQL 保留关键字时,使用反引号 ``

注意:如果您用表名表示列名,请使用如下反引号:

`table_name``column_name` .。

【讨论】:

【参考方案10】:

反引号通常用于表示identifier,也可以安全避免意外使用Reserved Keywords。

例如:

Use `database`;

这里的反引号将帮助服务器了解database 实际上是数据库的名称,而不是数据库标识符。

对表名和字段名也可以这样做。如果你用反引号包裹你的数据库标识符,这是一个非常好习惯

查看this 答案以了解有关反引号的更多信息。


现在关于双引号和单引号(Michael 已经提到过)。

但是,要定义一个值,您必须使用单引号或双引号。让我们看另一个例子。

INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, title1);

这里我故意忘记用引号包裹title1。现在服务器会将title1 作为列名(即标识符)。因此,要表明它是一个值,您必须使用双引号或单引号。

INSERT INTO `tablename` (`id, `title`) VALUES ( NULL, 'title1');

现在,结合 PHP,双引号和单引号使您的查询编写时间变得更加轻松。让我们看看您问题中查询的修改版本。

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

现在,在 PHP 中使用双引号,您将使变量 $val1$val2 使用它们的值,从而创建一个完全有效的查询。喜欢

$val1 = "my value 1";
$val2 = "my value 2";
$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

会做

INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, 'my value 1', 'my value 2')

【讨论】:

【参考方案11】:

结合 PHP 和 MySQL,双引号和单引号使您的查询编写时间变得如此轻松。

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";

现在,假设您在 MySQL 查询中使用直接 post 变量,然后这样使用它:

$query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (' ".$_POST['id']." ', ' ".$_POST['name']." ', ' ".$_POST['email']." ')";

这是在 MySQL 中使用 PHP 变量的最佳实践。

【讨论】:

因此双引号很灵活,但不能用作标识符。 请永远不要在查询中直接使用未转义的用户输入! @jankal 这只是示例。我指定如果您使用直接用户输入,那么 n 则............ @vipulsorathiya 请在您的回答中指定应该转义 POST 变量。您现在指向在查询中直接使用它们。不适合尝试这个的初学者...【参考方案12】:

单引号应用于字符串值,如 VALUES() 列表中的值。

反引号通常用于指示标识符,并且可以防止意外使用保留关键字。

结合 PHP 和 MySQL,双引号和单引号使您的查询编写时间变得更加轻松。

【讨论】:

【参考方案13】:

MySQL 和 PHP 中的字符串字面量是一样的。

字符串是字节或字符的序列,包含在 单引号 (“'”) 或双引号 (“"”) 字符。

所以如果你的字符串包含单引号,那么你可以使用双引号来引用字符串,或者如果它包含双引号,那么你可以使用单引号来引用字符串。但是如果你的字符串同时包含单引号和双引号,你需要转义用来引用字符串的那个。

大多数情况下,我们对 SQL 字符串值使用单引号,因此我们需要对 PHP 字符串使用双引号。

$query = "INSERT INTO table (id, col1, col2) VALUES (NULL, 'val1', 'val2')";

你可以在 PHP 的双引号字符串中使用一个变量:

$query = "INSERT INTO table (id, col1, col2) VALUES (NULL, '$val1', '$val2')";

但是如果$val1$val2 包含单引号,那会让你的SQL 出错。所以在sql中使用之前需要先对其进行转义;这就是mysql_real_escape_string 的用途。 (虽然准备好的语句更好。)

【讨论】:

【参考方案14】:

(关于您的问题的 SQL 性质,上面有很好的答案,但如果您是 PHP 新手,这也可能是相关的。)

也许值得一提的是,PHP 以不同的方式处理单引号和双引号字符串...

单引号字符串是“文字”,几乎是所见即所得的字符串。双引号字符串被 PHP 解释为可能的变量替换(PHP 中的反引号不完全是字符串;它们在 shell 中执行命令并返回结果)。

例子:

$foo = "bar";
echo 'there is a $foo'; // There is a $foo
echo "there is a $foo"; // There is a bar
echo `ls -l`; // ... a directory list

【讨论】:

以上是关于何时在 MySQL 中使用单引号、双引号和反引号的主要内容,如果未能解决你的问题,请参考以下文章

何时在 MySQL 中使用单引号、双引号和反引号

MySQL中单引号,双引号和反引号的区别

shell中对于单引号,双引号和反引号的处理方式

Shell中的单引号(‘)双引号(”)和反引号(·)

shell脚本中 的 单引号和反引号经常混淆,请高手帮我区别它们的功能,谢谢

何时使用三重单引号而不是三重双引号