SQL 为什么选择 0, ... 而不是 SELECT
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13219472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why SELECT 0, ... instead of SELECT
提问by Christian Kienle
Lets say I have a SQLite database that contains a table:
假设我有一个包含表的 SQLite 数据库:
sqlite> create table person (id integer, firstname varchar, lastname varchar);
Now I want to get every entry which is in the table.
现在我想获取表格中的每个条目。
sqlite> select t0.id, t0.firstname, t0.lastname from person t0;
This works fine and this it what I would use. However I have worked with a framework from Apple (Core Data) that generates SQL. This framework generates a slightly different SQL query:
这工作正常,这就是我会使用的。但是,我使用了 Apple(Core Data)的框架来生成 SQL。这个框架生成一个稍微不同的 SQL 查询:
sqlite> select 0, t0.id, t0.firstname, t0.lastname from person t0;
Every SQL query generated by this framework begins with "select 0,". Why is that?
此框架生成的每个 SQL 查询都以“select 0,”开头。这是为什么?
I tried to use the explain command to see whats going on but this was inconclusive - at least to me.
我尝试使用解释命令来查看发生了什么,但这是不确定的 - 至少对我而言。
sqlite> explain select t0.id, t0.firstname, t0.lastname from person t0;
addr opcode p1 p2 p3 p4 p5 comment
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
0 Trace 0 0 0 00 NULL
1 Goto 0 11 0 00 NULL
2 OpenRead 0 2 0 3 00 NULL
3 Rewind 0 9 0 00 NULL
4 Column 0 0 1 00 NULL
5 Column 0 1 2 00 NULL
6 Column 0 2 3 00 NULL
7 ResultRow 1 3 0 00 NULL
8 Next 0 4 0 01 NULL
9 Close 0 0 0 00 NULL
10 Halt 0 0 0 00 NULL
11 Transactio 0 0 0 00 NULL
12 VerifyCook 0 1 0 00 NULL
13 TableLock 0 2 0 person 00 NULL
14 Goto 0 2 0 00 NULL
And the table for the second query looks like this:
第二个查询的表如下所示:
sqlite> explain select 0, t0.id, t0.firstname, t0.lastname from person t0;
addr opcode p1 p2 p3 p4 p5 comment
---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
0 Trace 0 0 0 00 NULL
1 Goto 0 12 0 00 NULL
2 OpenRead 0 2 0 3 00 NULL
3 Rewind 0 10 0 00 NULL
4 Integer 0 1 0 00 NULL
5 Column 0 0 2 00 NULL
6 Column 0 1 3 00 NULL
7 Column 0 2 4 00 NULL
8 ResultRow 1 4 0 00 NULL
9 Next 0 4 0 01 NULL
10 Close 0 0 0 00 NULL
11 Halt 0 0 0 00 NULL
12 Transactio 0 0 0 00 NULL
13 VerifyCook 0 1 0 00 NULL
14 TableLock 0 2 0 person 00 NULL
15 Goto 0 2 0 00 NULL
回答by Christian Kienle
Some frameworks do this in order to tell, without any doubt, whether a row from that table was returned.
一些框架这样做是为了毫无疑问地判断是否返回了该表中的一行。
Consider
考虑
A B
+---+ +---+------+
| a | | a | b |
+---+ +---+------+
| 0 | | 0 | 1 |
+---+ +---+------+
| 1 | | 1 | NULL |
+---+ +---+------+
| 2 |
+---+
SELECT A.a, B.b
FROM A
LEFT JOIN B
ON B.a = A.a
Results
+---+------+
| a | b |
+---+------+
| 0 | 1 |
+---+------+
| 1 | NULL |
+---+------+
| 2 | NULL |
+---+------+
In this result set, it is not possible to see that a = 1
exists in table B, but a = 2
does not. To get that information, you need to select a non-nullable expression from table b, and the simplest way to do that is to select a simple constant value.
在这个结果集中,不可能看到a = 1
表 B中存在但a = 2
不存在。要获取该信息,您需要从表 b 中选择一个不可为空的表达式,而最简单的方法是选择一个简单的常量值。
SELECT A.a, B.x, B.b
FROM A
LEFT JOIN (SELECT 0 AS x, B.a, B.b FROM B) AS B
ON B.a = A.a
Results
+---+------+------+
| a | x | b |
+---+------+------+
| 0 | 0 | 1 |
+---+------+------+
| 1 | 0 | NULL |
+---+------+------+
| 2 | NULL | NULL |
+---+------+------+
There are a lot of situations where these constant values are not strictly required, for example when you have no joins, or when you could choose a non-nullable column from b instead, but they don't cause any harm either, so they can just be included unconditionally.
在很多情况下,这些常量值并不是严格要求的,例如当您没有连接时,或者当您可以从 b 中选择不可为空的列时,但它们也不会造成任何伤害,因此它们可以只是无条件地被包括在内。
回答by Glenn
When I have code to dynamically generate a WHERE
clause, I usually start the clause with a:
当我有动态生成WHERE
子句的代码时,我通常以以下内容开头子句:
WHERE 1 = 1
Then the loop to add additional conditions always adds each condition in the same format:
然后添加附加条件的循环总是以相同的格式添加每个条件:
AND x = y
without having to put conditional logic in place to check if this is the first condition or not: "if this is the first condition then start with the WHERE
keyword, else add the AND
keyword.
无需放置条件逻辑来检查这是否是第一个条件:“如果这是第一个条件,则从WHERE
关键字开始,否则添加AND
关键字。
So I can imagine a framework doing this for similar reasons. If you start the statement with a SELECT 0
then the code to add subsequent columns can be in a loop without any conditional statements. Just add , colx
each time without any conditional checking along the lines of "if this is the first column, don't put a comma before the column name, otherwise do".
所以我可以想象一个框架出于类似的原因这样做。如果以 a 开头语句,SELECT 0
则添加后续列的代码可以在没有任何条件语句的循环中。只需, colx
按照“如果这是第一列,不要在列名前放逗号,否则做”这样的行添加每次而不进行任何条件检查。
Example pseudo code:
示例伪代码:
String query = "SELECT 0";
for (Column col in columnList)
query += ", col";
回答by CL.
Only Apple knows … but I see two possibilities:
只有苹果知道……但我看到了两种可能性:
Inserting a dummy column ensures that the actualoutput columns are numbered beginning with 1, not 0. If some existing interface already assumed one-based numbering, doing it this way in the SQL backend might have been the easiest solution.
If you make a query for multiple objects using multiple subqueries, a value like this could be used to determine from which subquery a record originates:
SELECT 0, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 123 UNION ALL SELECT 1, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 456
(I don't know if Core Data actually does this.)
插入一个虚拟列可确保实际输出列从 1 开始编号,而不是从 0 开始。如果某些现有接口已经采用基于 1 的编号,那么在 SQL 后端这样做可能是最简单的解决方案。
如果您使用多个子查询查询多个对象,则可以使用这样的值来确定记录源自哪个子查询:
SELECT 0, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 123 UNION ALL SELECT 1, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 456
(我不知道 Core Data 是否真的这样做了。)
Your EXPLAIN
output shows that the only difference is (at address 4) that the second program sets the extra column to zero, so there is only a minimal performance difference.
您的EXPLAIN
输出显示唯一的区别是(在地址 4 处)第二个程序将额外的列设置为零,因此性能差异很小。