在Python和SQLite中使用反引号(`)或双引号(")。

17

我在Stack Overflow上看到一个类似的与Android有关的问题,但我想知道在使用Python时,选择表名或行id等等,我是否应该使用反引号(`)还是双引号(")。

我尝试过使用单引号 - 就像这样select 'rowid', * from 'tbl' order by 'rowid'。在某些情况下,单引号有效,但不是全部。我学会了使用双引号或反引号,并且我正在查看SQLite数据库浏览器,我注意到它使用反引号。

在Python中,我真的喜欢给我的字符串加上双引号,因为我来自Java,所以自然而然地会写成cursor.execute("select 'rowid',* from 'table';"),而且使用反引号也同样简单(使用双引号需要一个反斜杠,使查询看起来有些混乱)。

然而,我只是想确保反引号是可移植的(所有版本的WindowsLinuxOS X等)。


@Martijn Pieters 问题在于,当我使用单引号时,实际上得到了一个错误的输出。 - dylnmc
1
请注意,在此处您不能使用单引号,单引号仅用于文本字符串值:http://www.sqlite.org/lang_keywords.html - Martijn Pieters
嗯。出于某种原因 - 也许你可以解释一下 - 当我执行 "select 'rowid', * from table;" 时,我得到了 ('rowid', name,...)。正如laalto刚刚发布的那样 - "单引号用于字符串字面量,而不是标识符。" - dylnmc
抱歉,我混淆了术语。您需要使用双引号用于标识符。或者是反引号。或者是方括号。 - Martijn Pieters
1
在Python中,使用反引号表示字符串已经在2009年被弃用。问题中并不清楚反引号是在Python代码本身还是生成的(SQL)字符串输出中。 - Peter Mortensen
3个回答

43

SQL标准规定字符串必须使用'单引号',而标识符(例如表和列名)在用引号引起来时必须使用"双引号"

为了与MySQL兼容,SQLite也允许在上下文明确的情况下使用单引号表示标识符,双引号表示字符串。(在SELECT 'rowid' ...中,一个字符串是允许的,所以得到的就是一个字符串。)如果可能,请始终使用标准的SQL引号。

为了与MySQL兼容,SQLite还允许使用`反引号`表示标识符。

为了与Microsoft数据库兼容,SQLite还允许使用[方括号]表示标识符。

(这在所有SQLite版本中都适用。)


5

在引用标识符(例如列名或表名)时,请使用双引号。 这是SQL标准。

反引号也可以工作,但仅支持MySQL语法兼容性。

单引号用于字符串字面值,而不是标识符。这就是为什么使用它们时您将获得字面值的原因。

进一步阅读:SQLite关键字


1
但是反引号在任何地方都能起作用吗?为什么不利用这个优势来编写更简洁、更易读的代码呢? - dylnmc
3
会的,但如果你要编写新的 SQL,请优先使用双引号。 - laalto
@Dylan:反引号在任何地方都可以使用,SQLite 支持跨平台的语法。然而,双引号是标准且首选的形式。 - Martijn Pieters
1
我可以使用反引号,然后用替换全部(`)为(") :P - dylnmc

1

如果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'不等于任何整数值,因此返回为空。

在这个查询中,反引号的行为与未引用的valuevaluee相同,因为它不是关键字。但请注意,为了符合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.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接