如果mycol不存在,SQLite会将"mycol"
视为字符串,而反引号不会这样处理
因此,如果您在查询中有拼写错误并且列名错误,它将被视为字符串,而不是给出错误,这是任何理智人想要的。然而,反引号会报错。
使用反引号的优点是提供更好的错误检查,而双引号的巨大缺点当然是不符合标准SQL。
示例:
tmp.sql
CREATE TABLE "IntegerNames" ( value INTEGER NOT NULL, name TEXT NOT NULL );
INSERT INTO "IntegerNames" VALUES
(2, 'two'),
(3, 'three'),
(5, 'five')
;
SELECT '"value"';
SELECT * FROM "IntegerNames" WHERE "value" = 2;
SELECT '"valuee"';
SELECT * FROM "IntegerNames" WHERE "valuee" = 2;
SELECT '`value`';
SELECT * FROM "IntegerNames" WHERE `value` = 2;
SELECT '`valuee`';
SELECT * FROM "IntegerNames" WHERE `valuee` = 2;
SELECT 'value';
SELECT * FROM "IntegerNames" WHERE value = 2;
SELECT 'valuee';
SELECT * FROM "IntegerNames" WHERE valuee = 2;
运行:
rm -f tmp.sqlite && sqlite3 tmp.sqlite <tmp.sql
结果:
"value"
2|two
"valuee"
`value`
2|two
`valuee`
Error: near line 14: in prepare, no such column: valuee (1)
value
2|two
valuee
Error: near line 18: in prepare, no such column: valuee (1)
在使用"valuee"
时,我们发现没有错误:它只是被处理为一个字符串'value'
。然后SQLite会隐式地将所有内容类型转换,而'valuee'
不等于任何整数值,因此返回为空。
在这个查询中,反引号的行为与未引用的value
和valuee
相同,因为它不是关键字。但请注意,为了符合SQL标准,你必须选择包含大写字符的行(至少在PostgreSQL中要这样做),因此它们并不总是等价的,甚至不考虑关键字。
在SQLite 3.37.2,Ubuntu 22.04上进行了测试。
这种可怕的行为在这里有文档记录:https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted,开发人员自己承认这是一个坏主意,最初是由对MySQL兼容性的渴望所驱动的。他们现在已经学会更多地模仿PostgreSQL了 ;-)
8. Double-quoted String Literals Are Accepted
The SQL standard requires double-quotes around identifiers and single-quotes around string literals. For example:
- "this is a legal SQL column name"
- 'this is an SQL string literal'
SQLite accepts both of the above. But, in an effort to be compatible with MySQL 3.x (which was one of the most widely used RDBMSes when SQLite was first being designed) SQLite will also interpret a double-quotes string as string literal if it does not match any valid identifier.
This misfeature means that a misspelled double-quoted identifier will be interpreted as a string literal, rather than generating an error. It also lures developers who are new to the SQL language into the bad habit of using double-quoted string literals when they really need to learn to use the correct single-quoted string literal form.
In hindsight, we should not have tried to make SQLite accept MySQL 3.x syntax, and should have never allowed double-quoted string literals. However, there are countless applications that make use of double-quoted string literals and so we continue to support that capability to avoid breaking legacy.
As of SQLite 3.27.0 (2019-02-07) the use of a double-quoted string literal causes a warning message to be sent to the error log.
As of SQLite 3.29.0 (2019-07-10) the use of double-quoted string literals can be disabled at run-time using the SQLITE_DBCONFIG_DQS_DDL and SQLITE_DBCONFIG_DQS_DML actions to sqlite3_db_config(). The default settings can be altered at compile-time using the -DSQLITE_DQS=N compile-time option. Application developers are encouraged to compile using -DSQLITE_DQS=0 in order to disable the double-quoted string literal misfeature by default. If that is not possible, then disable double-quoted string literals for individual database connections using C-code like this:
sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DDL, 0, (void*)0);
sqlite3_db_config(db, SQLITE_DBCONFIG_DQS_DML, 0, (void*)0);
Or, if double-quoted string literals are disabled by default, but need to be selectively enabled for some historical database connections, that can be done using the same C-code as shown above except with the third parameter changed from 0 to 1.
"select 'rowid', * from table;"
时,我得到了('rowid', name,...)
。正如laalto刚刚发布的那样 - "单引号用于字符串字面量,而不是标识符。" - dylnmc