web-dev-qa-db-fra.com

SQL multiples colonnes dans la clause IN

Si nous avons besoin d'interroger une table en fonction d'un ensemble de valeurs pour une colonne donnée, nous pouvons simplement utiliser la clause IN. 

Mais si la requête doit être effectuée sur plusieurs colonnes, nous ne pouvons pas utiliser la clause IN (pris en compte dans les threads SO.) 

À partir d'autres threads SO, nous pouvons contourner ce problème à l'aide de clauses de jointures ou de clauses existentes, etc. Mais ils fonctionnent tous si la table principale et les données de recherche sont dans la base de données. 

E.g
User table:
firstName, lastName, City

Étant donné une liste de tuples (prénom, nom), je dois obtenir les villes. 

Je peux penser aux solutions suivantes. 

1

Construire une requête select comme, 

SELECT city from user where (firstName=x and lastName=y) or (firstName=a and lastName=b) or .....

2

Téléchargez toutes les valeurs firstName, lastName dans une table intermédiaire et effectuez une jointure entre la table 'utilisateur' et la nouvelle table intermédiaire. 

Existe-t-il des options pour résoudre ce problème et quelle est la solution préférée pour résoudre ce problème en général?

29
Htaras

Vous pourriez faire comme ça:

SELECT city FROM user WHERE (firstName, lastName) IN (('a', 'b'), ('c', 'd'));

Le sqlfiddle.

68
xdazz

En fin de compte, il est souvent plus facile de charger vos données dans la base de données, même s'il ne s'agit que d'exécuter une requête rapide. Les données codées en dur semblent rapides à entrer, mais cela devient vite pénible si vous devez commencer à apporter des modifications.

Toutefois, si vous souhaitez coder les noms directement dans votre requête, voici une méthode plus simple pour le faire:

with names (fname,lname) as (
    values
        ('John','Smith'),
        ('Mary','Jones')
)
select city from user
    inner join names on
        fname=firstName and
        lname=lastName;

L'avantage de ceci est qu'il sépare quelque peu vos données de la requête.

(Ceci est la syntaxe DB2; il faudra peut-être un peu de peaufinage sur votre système).

5
dan1111

Dans Oracle, vous pouvez faire ceci:

SELECT * FROM table1 WHERE (col_a,col_b) IN (SELECT col_x,col_y FROM table2)
4
grokster

Assurez-vous de disposer d'un index sur vos colonnes de prénom et de nom de famille et utilisez 1. Cela n'aura pas vraiment d'impact sur les performances.

EDIT: Après le commentaire de @Dems concernant le spamming du cache de plan, une meilleure solution pourrait être de créer une colonne calculée sur la table existante (ou une vue séparée) contenant une valeur concaténée Firstname + Lastname, permettant ainsi l'exécution une requête telle que 

SELECT City 
FROM User 
WHERE Fullname in (@fullnames)

@fullnames ressemble un peu à "'JonDoe', 'JaneDoe'" etc

1
Jaimal Chohan

En général, vous pouvez facilement écrire la condition Where comme ceci:

select * from tab1
where (col1, col2) in (select col1, col2 from tab2)

Remarque
Oracle ignore les lignes où une ou plusieurs des colonnes sélectionnées sont NULL. Dans ces cas, vous voudrez probablement utiliser la fonction NVL - pour mapper NULL sur une valeur spéciale (qui ne doit pas figurer dans les valeurs):

select * from tab1
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2)

Oraclesql

1
Alexander Roskamp

Déterminez si la liste de noms est différente avec chaque requête ou réutilisée. S'il est réutilisé, il appartient à la base de données.

Même si elle est unique avec chaque requête, il peut être utile de la charger dans une table temporaire (syntaxe #table) pour des raisons de performances. Dans ce cas, vous pourrez éviter la recompilation d'une requête complexe.

Si le nombre maximal de noms est fixe, vous devez utiliser une requête paramétrée.

Cependant, si aucun des cas ci-dessus ne s'applique, je choisirais d'inclure les noms dans la requête, comme dans votre approche n ° 1.

0
Jirka Hanika