我正在尝试学习编写查询的最佳方法。 我也理解保持一致的重要性。 到现在为止,我已经随机使用单引号,双引号和反引号而没有任何实际想法。
例:
$query = 'INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)';
此外,在上面的示例中,考虑table,col1,val1等可以是变量。
这是什么标准? 你是做什么?
我一直在这里阅读类似问题的答案大约20分钟,但似乎没有明确答案这个问题。 sub>
请注意,这是一个特定于MySQL的问题。 一般而言,SQL(即ISO / ANSI SQL)具有不同的引号集:双引号用于分隔标识符,例如, "tablename",单引号用于文字,例如'this is a some text'。 反向标记从不在标准SQL中使用。 (如果需要在标识符中包含双引号,请将其键入两次"odd""tablename"。同样,文字中的双引号,如'Conan O''Brien'。)
反引号用于表和列标识符,但仅在标识符是MySQL保留关键字时,或者当标识符包含空格字符或超出有限集的字符时才需要(见下文)。通常建议避免使用保留关键字尽可能作为列或表标识符,避免引用问题。
单引号应该用于VALUES()列表中的字符串值。 MySQL也支持双引号用于字符串值,但单引号被其他RDBMS更广泛地接受,因此使用单引号而不是双引号是一个好习惯。
MySQL还希望DATE和DATETIME文字值单引号为'2001-01-01 00:00:00'之类的字符串。有关更多详细信息,请参阅日期和时间文字文档,特别是在日期字符串中使用连字符-作为段分隔符的替代方法。
因此,使用您的示例,我会双引号PHP字符串并在值'val1', 'val2'上使用单引号。 NULL是MySQL关键字和特殊(非)值,因此不带引号。
这些表或列标识符都不是保留字或使用需要引用的字符,但我还是用反引号引用它们(稍后会详细介绍......)。
不应引用RDBMS本机函数(例如,MySQL中的NOW()),尽管它们的参数受到已经提到的相同字符串或标识符引用规则的约束。
Backtick (`)
table & column ───────┬─────┬──┬──┬──┬────┬──┬────┬──┬────┬──┬───────┐
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
$query ="INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `updated`)
VALUES (NULL, 'val1', 'val2', '2001-01-01', NOW())";
↑↑↑↑ ↑ ↑ ↑ ↑ ↑↑ ↑↑↑↑↑
Unquoted keyword─────┴┴┴┘ │ │ │ │ ││ │││││
Single-quoted (') strings ───────────┴────┴──┴────┘ ││ │││││
Single-quoted (') DATE ───────────────────────────┴──────────┘ │││││
Unquoted function─────────────────────────────────────────┴┴┴┴┘
可变插值
变量的引用模式不会改变,但如果您打算直接在字符串中插入变量,则必须在PHP中使用双引号。只需确保已正确转义变量以便在SQL中使用。 (建议使用支持预处理语句的API,以防止SQL注入)。
// Same thing with some variable replacements
// Here, a variable table name $table is backtick-quoted, and variables
// in the VALUES list are single-quoted
$query ="INSERT INTO `$table` (`id`, `col1`, `col2`, `date`) VALUES (NULL, '$val1', '$val2', '$date')";
准备好的陈述
使用准备好的语句时,请查阅文档以确定是否必须引用语句的占位符。 PHP,PDO和MySQLi中最流行的API可以使用未加引号的占位符,其他语言中的大多数预处理语句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 (?, ?, ?, ?)";
需要在标识符中引用反引号的字符:
根据MySQL文档,您不需要使用以下字符集引用(反引号)标识符:
ASCII: [0-9,a-z,A-Z$_] (basic Latin letters, digits 0-9, dollar, underscore)
您可以使用超出该组的字符作为表或列标识符,例如包括空格,但是您必须引用(反引号)它们。
"但单引号被其他RDBMS更广泛接受" - 使用单引号作为字符串文字由SQL标准定义(和必需)
@a_horse_with_no_name几乎没有人使用ANSI MySQL('|'用于字符串连接 - 真的吗?)
这不是真的:"MySQL还希望DATE和DATETIME文字值单引号为'2001-01-01 00:00:00'之类的字符串"
@Kick_the_BUCKET你有其他建议吗?保留它们不带引号会导致它们被解释为整数运算。确实可以使用与-不同的分隔符,但除非没有分隔符,否则引用是必要的/doc/refman/5.7/en/date-and-time-literals.html
MySQL密钥/保留字:/doc/refman/5.7/en/keywords.html
列别名和表别名怎么样,如在select col1 as c from my_table中,对于别名"c",用单引号或反引号包装它更好吗?
@evilReiko MySQL文档似乎没有明确地解决别名引用。它将接受单个,双重或反引号的别名,但可能会受到不同ANSI SQL模式的影响。我不确定SQL规范对别名引号的要求 - 个人偏好:为了保持一致性,我引用它们与列标识符相同 - 也就是说,如果需要,我要么反复引用它们,要么如果没有则不引用它们。我不对别名使用单引号或双引号。
@MichaelBerkowski如果别名是保留关键字,则需要引用别名。 SQL标准是字符串文字和日期用单引号括起来。对象/实体用双引号括起来。 MySQL使用反引号``是一个奇怪的(尽管普遍存在)异常,而SQL Server使用方括号[]是一种奇怪的(虽然普遍存在)异常。在这两种情况下,都可以使用双引号,我个人认为这是一个好主意,因为它增强了跨不同SQL方言的可移植性和可读性。
但是,如果单引号用于字符串值,而最外面的引号也是单引号,则整行看起来像:'INSERT INTO `$table` (`id`, `col1`, `col2`, `date`) VALUES (NULL, \'' . $val1 . '\', \'' . $val2 . '\', \'' . $date . '\')';。这会影响可读性。
使用双引号进行sql查询是否容易受到php变量注入?像:"SELECT * FROM $my_table",url查询类似于?mytable=$all_tables?
@GuneyOzsan是的,非常脆弱。除非已根据可接受的表名列表进行验证,否则永远不要将变量用于表名 - 创建一个允许的名称数组并检查变量是否与列表中的内容匹配以使其安全使用。否则,您无法安全地转义表名变量以供使用。
MySQL中有两种类型的引号:
'用于包含字符串文字
`用于包含表和列名称等标识符
然后有"这是一个特例。根据MySQL服务器的sql_mode,它可以一次用于上述目的之一:
默认情况下,"字符可用于包围字符串文字,就像'一样
在ANSI_QUOTES模式下,"字符可用于包围标识符,就像`一样
以下查询将根据SQL模式生成不同的结果(或错误):
ANSI_QUOTES已禁用
查询将选择字符串文字"column",其中列foo等于字符串"bar"
ANSI_QUOTES已启用
查询将选择列column,其中列foo等于列bar
什么时候用
我建议您避免使用",以便您的代码独立于SQL模式
总是引用标识符,因为这是一个很好的做法(关于SO的很多问题讨论这个)
(关于你的问题的SQL性质,上面有很好的答案,但如果你是PHP的新手,这也可能是相关的。)
也许重要的是要提到PHP处理单引号和双引号字符串不同...
单引号字符串是'文字',几乎是WYSIWYG字符串。 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
反引号通常用于表示identifier,并且不会意外地使用保留关键字。
例如:
Use `database`;
这里的反引号将帮助服务器理解database实际上是数据库的名称,而不是数据库标识符。
可以对表名和字段名执行相同的操作。如果用反引号包装数据库标识符,这是一个非常好的习惯。
Check this answer to understand more about backticks.
现在关于双引号和单引号(迈克尔已经提到过)。
但是,要定义一个值,您必须使用单引号或双引号。让我们看另一个例子。
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')
在MySQL中,这些符号用于分隔查询`,",'和()。
"或'用于包含类似字符串的值"26-01- 00:00:00"或'26-01- 00:00:00'。这些符号仅用于字符串,而不是now,sum或max等聚合函数。
`用于封闭表名或列名,例如select `column_name` from `table_name` where id='2'
(和)只是包含查询的部分内容,例如select `column_name` from `table_name` where (id='2' and gender='male') or name='rakesh'。
MySQL和PHP中的字符串文字是相同的。
A string is a sequence of bytes or characters, enclosed within either
single quote ("'") or double quote (""") characters.
因此,如果您的字符串包含单引号,那么您可以使用双引号来引用字符串,或者如果它包含双引号,那么您可以使用单引号来引用字符串。但是,如果您的字符串包含单引号和双引号,则需要转义用于引用字符串的字符串。
大多数情况下,我们对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的用途。 (虽然准备好的陈述更好。)
这里有很多有用的答案,通常最终分为两点。
BACKTICKS(`)用于标识符名称。
单引号(')用于值。
和@MichaelBerkowski说
Backticks are to be used for table and column identifiers, but are
only necessary when the identifier is a MySQL reserved keyword, or
when the identifier contains whitespace characters or characters
beyond a limited set (see below) It is often recommended to avoid
using reserved keywords as column or table identifiers when possible,
avoiding the quoting issue.
但是有一种情况,即标识符既不是保留关键字,也不包含有限集之外的空格或字符,但必须围绕它们进行反引号。
例
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也是一个指数。
结合PHP和MySQL,双引号和单引号使您的查询编写时间变得更加容易。
$query ="INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, '$val1', '$val2')";
现在,假设您正在使用直接post变量进入MySQL查询,那么使用它:
$query ="INSERT INTO `table` (`id`, `name`, `email`) VALUES ('".$_POST['id']." ', '".$_POST['name']." ', '".$_POST['email']." ')";
这是将PHP变量用于MySQL的最佳实践。
因此,双引号是灵活的,但不能用作标识符。
请勿在查询中直接使用未转义的用户输入!
@jankal这只是例子。我指定如果你使用直接用户输入那么n然后...........
@vipulsorathiya请在答案中指明POST变量应该被转义。您现在指的是直接在查询中使用它们。试试这个的初学者不好...
如果表cols和values是变量,那么有两种方法:
使用双引号""完整查询:
$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保留关键字时,请使用返回ticks ``。
注意:如果您使用表名表示列名,那么请使用这样的返回标记:
`table_name`。 `column_name` < - 注意:从后面的刻度中排除.。
单引号应该用于字符串值,如VALUES()列表中所示。
反引号通常用于表示标识符,并且不会意外地使用保留关键字。
结合PHP和MySQL,双引号和单引号使您的查询编写时间变得更加容易。
除了所有(解释清楚的)答案之外,还没有提到以下内容,我经常访问此问答。
简而言之; MySQL认为你想在自己的表/列上进行数学运算,并将诸如"电子邮件"之类的连字符解释为e减去mail。
免责声明:所以我认为我会将此作为"FYI"类型的答案添加到那些完全不熟悉数据库并且可能不理解已经描述的技术术语的人那里。
SQL服务器和MySQL,PostgreySQL,Oracle不理解双引号(")。因此,您的查询应该没有双引号("),并且应该只使用单引号(')。
回溯(`)是在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\'';
当我们必须为动态分配一些值并执行一些字符串连接时,会出现double(")或single(')引号的问题:
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 + '\'';
如果需要进一步清除,请遵循JavaScript中的引号