2010-02-05 17 views
0

Y at-il une meilleure façon d'écrire ce SQL que d'utiliser WHERE ... IN (sous-requête)?Existe-t-il un meilleur moyen d'écrire ce SQL que d'utiliser WHERE ... IN (sous-requête)?

SELECT device.mac, reseller.name, agent.name 
    FROM device 
    LEFT JOIN global_user 
    ON device.global_user_id = global_user.id 
    LEFT JOIN agent 
    ON global_user.id = agent.global_user_id 
    LEFT JOIN reseller 
    ON global_user.id = reseller.global_user_id 
     OR agent.reseller_id = reseller.id 
    WHERE device.global_user_id IN (
    SELECT global_user_id 
     FROM reseller 
     WHERE id = '200' 
) OR device.global_user_id IN (
    SELECT global_user_id 
     FROM agent 
     WHERE reseller_id = '200' 
); 

im essayant d'obtenir une liste de tous les appareils, avec quelques détails revendeur/agent, sous un revendeur particulier. Cela inclut les périphériques attribués directement au revendeur et les périphériques attribués aux agents sous le revendeur. reseller.id est unique. il sera exécuté sur la base de données postgresql.

Les périphériques sont affectés à la fois aux agents et aux revendeurs. les agents sont affectés aux revendeurs.

cette requête fonctionne, mais je n'ai pas souvent utilisé un OR dans un JOIN et j'essaie généralement d'éviter les sous-requêtes. Ce concept de requête sera souvent utilisé, donc je voudrais m'assurer que je n'ai pas oublié quelque chose.

merci pour vos commentaires.

+0

Alors, quelle est la question? –

+0

Est-ce que reseller.id est unique? –

+0

la question, comme il apparaît dans le titre, est "est-il un meilleur moyen d'écrire ce SQL que d'utiliser WHERE ... IN (sous-requête)?" Je l'ai ajouté au corps pour plus de clarté. –

Répondre

3

Vous pouvez donner à ce tourbillon:

SELECT device.mac, reseller.name, agent.name 
    FROM device 
    JOIN 
    (
     SELECT global_user_id 
     FROM reseller 
     WHERE id = '200' 
     UNION 
     SELECT global_user_id 
     FROM agent 
     WHERE reseller_id = '200' 
) r ON device.global_user_id = r.global_user_id 
    LEFT JOIN global_user 
    ON device.global_user_id = global_user.id 
    LEFT JOIN agent 
    ON global_user.id = agent.global_user_id 
    LEFT JOIN reseller 
    ON global_user.id = reseller.global_user_id 
     OR agent.reseller_id = reseller.id 

Précision: toujours une bonne idée d'essayer différentes variations d'une requête pour vous assurer que vous vous retrouvez avec la plus performante requête (bien que souvent, différentes variantes entraînent la génération du même plan d'exécution par l'optimiseur de requête). Du point de vue de SQL Server, l'ordre dans lequel la requête est traitée signifie que les JOINs sont traités avant la clause WHERE. Donc, en théorie, cette approche JOIN devrait réduire l'ensemble des résultats plus tôt.

+0

Pour plus de clarté, pourquoi l'utiliseriez-vous à la place de la requête d'origine? –

+0

@NickLarsen - clarification ajoutée – AdaTheDev

+0

@AdaTheDev Vous faites un excellent point sur la jointure, pour un peu plus de lecture à tous ceux qui visitent ce fil, consultez cet article sur l'ordre des opérations pour les requêtes du serveur sql, http: //www.bennadel .com/blog/70-SQL-Query-Order-of-Operations.htm –

1

Que pensez-vous de cela?

SELECT d.mac, r.name, a.name 
FROM device as d, global_user as g, agent as a, reseller as r 
WHERE d.global_user_id = g.id 
    AND g.id = a.global_user_id 
    AND (g.id = r.global_user_id OR a.reseller_id = r.id) 
    AND (r.id = '200' OR a.reseller_id = '200'); 
+0

Parce que revendeur.id est unique à partir des commentaires commentaires d'affiches originales. J'irais toujours avec les clauses ON, mais le point était que vous pouvez supprimer les sous-requêtes tous ensemble. –

+0

Certaines versions de base de données pourraient optimiser cela, mais cela détruirait probablement les performances sur la plupart des serveurs. Cela dit, c'est succinct. – eswald

+0

@Wade cela n'affichera pas les périphériques affectés directement au revendeur. ceci montrera seulement les dispositifs assignés à un agent. Cela produira un jeu de résultats incorrect. –

1

J'essaie d'éviter les sous-requêtes et IN clause s'il est facile de les remplacer. Si je vous ai bien compris DB model, cette requête devrait produire le même résultat:

SELECT  DISTINCT 
      device.mac, reseller.name, agent.name 
FROM  device 
LEFT JOIN global_user 
     ON device.global_user_id = global_user.id 
LEFT JOIN agent 
     ON global_user.id = agent.global_user_id 
LEFT JOIN reseller 
     ON global_user.id = reseller.global_user_id 
     OR agent.reseller_id = reseller.id 
WHERE  reseller.id = '200' 
     OR agent.reseller_id = '200' 
+0

@van avant que je commence à utiliser les sous-requêtes, j'ai presque eu votre suggestion en cours d'utilisation, mais j'étais légèrement éteint. cela produit le jeu de résultats correct, sans l'utilisation de sous-requêtes. –

+0

@van lors de l'exécution de cette requête sur un ensemble de données plus volumineux, il faut 40 secondes pour renvoyer un résultat, contrairement à ma requête initiale qui prend 2,5 secondes. –

+0

@ dan2342: très bien peut-être que cette requête n'est pas optimale. Idéalement, vous pouvez le diviser en deux requêtes en naviguant sur 2 des chemins possibles de 'device' à' revendeur'. En outre, si la requête avec sous-sélection fait d'abord une si bonne performance, je peux supposer que vous pourriez manquer certains 'indices 'sur la base de données qui pourraient être la clé pour la performance de votre requête. – van