web-dev-qa-db-fra.com

Pourquoi SELECT 0, ... au lieu de SELECT

Disons que j'ai une base de données SQLite qui contient une table:

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

Maintenant, je veux obtenir chaque entrée qui est dans la table.

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

Cela fonctionne bien et c'est ce que j'utiliserais. Cependant, j'ai travaillé avec un framework Apple (Core Data) qui génère du SQL. Ce framework génère une requête SQL légèrement différente:

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

Chaque requête SQL générée par ce framework commence par "select 0". Pourquoi donc?

J'ai essayé d'utiliser la commande explicit pour voir ce qui se passait, mais ce n'était pas concluant - du moins pour moi.

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 

Et la table pour la deuxième requête ressemble à ceci:

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     
21
Christian Kienle

Certains frameworks le font afin de dire, sans aucun doute, si une ligne de cette table a été retournée.

Considérer

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

Dans cet ensemble de résultats, il n'est pas possible de voir que a = 1 existe dans la table B, contrairement à a = 2. Pour obtenir ces informations, vous devez sélectionner une expression non nullable dans la table b, et le moyen le plus simple consiste à sélectionner une valeur constante simple.

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

Il existe de nombreuses situations dans lesquelles ces valeurs constantes ne sont pas strictement requises, par exemple, lorsque vous n'avez pas de jointures ou que vous pouvez choisir une colonne non nullable dans b, mais qu'elles ne causent pas de dommages non plus. juste être inclus sans condition.

16
user743382

Quand j'ai du code pour générer dynamiquement une clause WHERE, je commence généralement la clause par:

WHERE 1 = 1

Ensuite, la boucle pour ajouter des conditions supplémentaires ajoute toujours chaque condition dans le même format:

AND x = y

sans avoir à mettre en place une logique conditionnelle pour vérifier s’il s’agit ou non de la première condition: "s’il s’agit de la première condition, commencez par le mot clé WHERE, sinon ajoutez le mot clé AND.

Je peux donc imaginer un cadre faisant cela pour des raisons similaires. Si vous démarrez l'instruction avec un SELECT 0, le code permettant d'ajouter les colonnes suivantes peut se trouver dans une boucle sans instructions conditionnelles. Il suffit d’ajouter , colx à chaque fois sans vérification conditionnelle le long de la ligne "s'il s'agit de la première colonne, ne mettez pas de virgule avant le nom de la colonne, sinon faites".

Exemple de pseudo-code:

String query = "SELECT 0";

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

Seul Apple sait… mais je vois deux possibilités:

  1. L'insertion d'une colonne factice garantit que les colonnes actual output sont numérotées en commençant par 1, et non par 0. Si une interface existante supposait déjà une numérotation à une base, cette manière de procéder dans le backend SQL aurait pu être la solution la plus simple.

  2. Si vous effectuez une requête pour plusieurs objets à l'aide de plusieurs sous-requêtes, une valeur comme celle-ci peut être utilisée pour déterminer la sous-requête d'un enregistrement:

    SELECT 0, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 123
    UNION ALL
    SELECT 1, t0.firstname, ... FROM PERSON t0 WHERE t0.id = 456 
    

    (Je ne sais pas si Core Data le fait réellement.)


Votre sortie EXPLAIN indique que la seule différence est (à l'adresse 4) que le deuxième programme définit la colonne supplémentaire sur zéro, de sorte qu'il n'y a qu'une différence de performance minimale.

0
CL.