2009-09-25 6 views
12

Etant donnée une base de données comme ceci:utilisant tuples sql à la clause

BEGIN TRANSACTION; 
CREATE TABLE aTable (
a STRING, 
b STRING); 
INSERT INTO aTable VALUES('one','two'); 
INSERT INTO aTable VALUES('one','three'); 
CREATE TABLE anotherTable (
a STRING, 
b STRING); 
INSERT INTO anotherTable VALUES('one','three'); 
INSERT INTO anotherTable VALUES('two','three'); 
COMMIT; 

Je voudrais faire quelque chose le long des lignes de

SELECT a,b FROM aTable 
WHERE (aTable.a,aTable.b) IN 
(SELECT anotherTable.a,anotherTable.b FROM anotherTable); 

Pour obtenir la réponse « un », « trois » , mais j'obtiens "près", ": erreur de syntaxe"

Est-ce possible dans n'importe quelle saveur de SQL? (J'utilise sqlite)

Est-ce que je fais une erreur conceptuelle grossière? Ou quoi?

Répondre

18

votre code fonctionne si vous le faites dans PostgreSQL ou Oracle. sur MS SQL, il est pas pris en charge

utiliser ceci:

SELECT a,b FROM aTable 
WHERE 
-- (aTable.a,aTable.b) IN -- leave this commented, it makes the intent more clear 
EXISTS 
(
    SELECT anotherTable.a,anotherTable.b -- do not remove this too, perfectly fine for self-documenting code, i.e.. tuple presence testing 
    FROM anotherTable 
    WHERE anotherTable.a = aTable.a AND anotherTable.b = aTable.b 
); 

[EDIT]

sans l'énonciation d'intention:

SELECT a,b FROM aTable 
WHERE  
EXISTS 
(
    SELECT * 
    FROM anotherTable 
    WHERE anotherTable.a = aTable.a AND anotherTable.b = aTable.b 
); 

il est un peu boiteux, plus d'un décennie, MS SQL n'a toujours pas de support de première classe pour les tuples. La construction de tuple est beaucoup plus lisible que sa construction EXISTS analogue. btw, JOIN fonctionne également (code de tster), mais si vous avez besoin de quelque chose de plus flexible et pérenne, utilisez EXISTS.

[EDIT]

parlant de SQLite, je barboter avec récemment. Oui, IN tuples ne fonctionne pas

+0

réponse définitive en 10 minutes! ne fonctionne pas dans sqlite :-( voté et accepté –

+0

Même si cela a fonctionné dans sqlite, je vous recommande de ne pas le faire.Cela est de confondre les futurs responsables de votre code. (NOTE: vous êtes le futur mainteneur, donc c'est vous qui serez confus) – tster

+4

@tster - Je ne vois pas la source de toute confusion –

2

vous pouvez utiliser une jointure:

SELECT aTable.a, aTable.b FROM aTable 
JOIN anotherTable ON aTable.a = anotherTable.a AND aTable.b = anotherTable.b 
+0

Cela fonctionne. Plus la réponse est apparue en 5 minutes! Toujours intéressé de savoir si mon code proposé est possible/désespérément erroné/peu importe? –

+0

Oui, vous essayez d'écrire d'une manière que vous comprenez, mais ce problème est résolu beaucoup plus naturellement en utilisant la théorie des ensembles, la base de SQL. Une utilisation très courante de SQL consiste à joindre deux tables pour en obtenir l'intersection, ce que vous essayez de faire. – RedFilter

+0

@OrbMan: IN est plus intuitif; JOIN par moments, c'est trop regarder l'informatique. Et c'est juste une question d'avoir plus de construction de première classe à partir d'un langage pour pouvoir accomplir quelque chose de plus facile (pensez aux propriétés de C# vs Java setter/getter). Si l'IN fonctionne pour une valeur unique, je pense que vous serez plus que content si le SGBDR que vous utilisez fonctionne aussi sur des valeurs appariées (tuples) –

1

Une autre alternative consiste à utiliser concaténation pour faire de votre 2-tuple dans un seul champ:

SELECT a,b FROM aTable 
WHERE (aTable.a||'-'||aTable.b) IN 
(SELECT (anotherTable.a || '-' || anotherTable.b FROM anotherTable); 

... juste être conscient que de mauvaises choses peuvent se produire si un ou b contient le délimiteur '-'

+1

Cette solution aurait un autre inconvénient: l'optimiseur de requêtes ne peut pas raisonner sur de telles expressions et ne peut donc pas optimiser la requête. – iuzuz

Questions connexes