为什么选择SELECT 0,...而不是SELECT

时间:2012-11-04 14:39:28

标签: sql sqlite core-data

假设我有一个包含表格的SQLite数据库:

sqlite> create table person (id integer, firstname varchar, lastname varchar);

现在我想获得表格中的每个条目。

sqlite> select t0.id, t0.firstname, t0.lastname from person t0;

这很好用,这就是我要用的。但是,我使用了生成SQL的Apple(Core Data)框架。该框架生成略有不同的SQL查询:

sqlite> select 0, t0.id, t0.firstname, t0.lastname from person t0;

此框架生成的每个SQL查询都以“select 0”开头。那是为什么?

我尝试使用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 

第二个查询的表格如下所示:

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     

3 个答案:

答案 0 :(得分:16)

有些框架这样做是为了毫无疑问地告诉我是否返回了该表中的一行。

考虑

  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 |
+---+------+

在此结果集中,无法看到表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 |
+---+------+------+

在很多情况下,这些常量值并非严格要求,例如,当您没有连接时,或者您可以从b中选择不可为空的列时,但它们也不会造成任何伤害,所以他们可以无条件地包括在内。

答案 1 :(得分:8)

当我有动态生成WHERE子句的代码时,我通常用以下内容启动该子句:

WHERE 1 = 1

然后,添加附加条件的循环总是以相同的格式添加每个条件:

AND x = y

无需放置条件逻辑来检查这是否是第一个条件:“如果这是第一个条件,则以WHERE关键字开头,否则添加AND关键字。

所以我可以想象一个框架这样做是出于类似的原因。如果使用SELECT 0启动语句,则添加后续列的代码可以在没有任何条件语句的循环中。只需每次添加, colx而不进行任何条件检查,如果这是第一列,请不要在列名前加上逗号,否则执行“。

伪代码示例:

String query = "SELECT 0";

for (Column col in columnList)
    query += ", col";

答案 2 :(得分:0)

只有Apple知道......但我看到两种可能性:

  1. 插入虚拟列可确保实际输出列的编号从1开始,而不是0.如果某些现有接口已经假设基于一个编号,则在SQL中执行此操作后端可能是最简单的解决方案。

  2. 如果使用多个子查询查询多个对象,可以使用这样的值来确定记录来自哪个子查询:

    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是否真的这样做了。)


  3. 您的EXPLAIN输出显示唯一的区别是(在地址4处)第二个程序将额外列设置为零,因此只有最小的性能差异。