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:
这很好,这就是我要用的。然而,我使用了一个来自苹果的框架(核心数据)来生成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.
我试着使用explain命令来查看发生了什么,但这是不确定的——至少对我来说是这样。
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
15
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.
在这个结果集中,不可能在表B中看到a = 1,但是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中选择一个非空列,但是它们也不会造成任何伤害,因此可以无条件地包含它们。
8
When I have code to dynamically generate a WHERE
clause, I usually start the clause with a:
当我有代码动态生成WHERE子句时,我通常以a开头:
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".
我可以想象一个框架出于类似的原因这样做。如果以SELECT 0开始语句,则添加后续列的代码可以在循环中,不包含任何条件语句。只需添加colx,每次都不需要任何条件检查,比如“如果这是第一列,不要在列名前加逗号,否则就这样做”。
Example pseudo code:
伪代码示例:
String query = "SELECT 0";
for (Column col in columnList)
query += ", col";
0
Only Apple knows … but I see two possibilities:
只有苹果知道……但我认为有两种可能性:
Inserting a dummy column ensures that the actual output 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.
插入一个假列可以确保实际的输出列以1开头,而不是0开头。如果一些现有的接口已经采用了基于一个的编号方式,那么在SQL后端使用这种方式可能是最简单的解决方案。
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.)
(我不知道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)是第二个程序将额外的列设置为零,因此只有最小的性能差异。