2010-02-24 5 views
3

Voici mon schéma:MySQL: Comment condenser cette requête verbeuse?

Fournisseurs (sid: entiers, sname: string, chaîne d'adresse)

Pièces (pid: entiers, pname: string, couleur: string)

catalogue (sid: entier, pid: entier, coût: real)

clés primaires en gras.

Voici la requête MySQL Je travaille avec:

-- Find the sids of suppliers who supply every red part or supply every green part. 
-- this isn't DRY 
-- not tested 
SELECT Suppliers.sid 
FROM Suppliers 
JOIN (SELECT sid, COUNT(Parts.pid) AS partsPerSupplier 
    FROM Catalog 
    JOIN Parts on Catalog.pid = Parts.pid 
    WHERE Parts.color = "red" 
    GROUP BY sid) 
AS partCounts ON Suppliers.sid = partCounts.sid 
JOIN (SELECT COUNT(pid) AS totalParts 
    FROM Parts 
    WHERE color = "red" 
) AS totalPartsTable ON totalPartsTable.totalParts = partCounts.partsPerSupplier 
UNION 
SELECT Suppliers.sid 
FROM Suppliers 
JOIN (SELECT sid, COUNT(Parts.pid) AS partsPerSupplier 
    FROM Catalog 
    JOIN Parts on Catalog.pid = Parts.pid 
    WHERE Parts.color = "green" 
    GROUP BY sid) 
AS partCounts ON Suppliers.sid = partCounts.sid 
JOIN (SELECT COUNT(pid) AS totalParts 
    FROM Parts 
    WHERE color = "green" 
) AS totalPartsTable ON totalPartsTable.totalParts = partCounts.partsPerSupplier; 

Les sous-requêtes de chaque côté de la déclaration UNION sont hideusement répétées. Dans la programmation impérative, ce serait un bon endroit pour faire une fonction, en prenant la couleur comme paramètre. Quel est l'équivalent de ceci dans MySQL?

J'ai entendu parler de « vues », mais je pense que cela pourrait être surpuissant pour ce cas.

Répondre

1

Ce:

SELECT * 
FROM suppliers s 
WHERE EXISTS 
     (
     SELECT NULL 
     FROM (
       SELECT 'red' AS color 
       UNION ALL 
       SELECT 'green' 
       ) ci 
     WHERE color NOT IN 
       (
       SELECT color 
       FROM parts p 
       WHERE p.pid NOT IN 
         (
         SELECT pid 
         FROM catalog c 
         WHERE c.sid = s.sid 
         ) 
       ) 
     ); 

ou ceci:

SELECT c.sid 
FROM (
     SELECT color, COUNT(*) AS total 
     FROM parts 
     WHERE color IN ('red', 'green') 
     GROUP BY 
       color 
     ) t 
JOIN parts p 
ON  p.color = t.color 
JOIN catalog c 
ON  c.pid = p.pid 
GROUP BY 
     sid, color 
HAVING COUNT(*) = total; 
+0

Pouvez-vous expliquer comment cette requête fonctionne? –

+0

Cela provoque un message d'erreur: # 1064 - Vous avez une erreur dans votre syntaxe SQL; consultez le manuel qui correspond à votre version du serveur MySQL pour la bonne syntaxe à utiliser près de 'LEFT JOIN catalogue c ON c.pid = p.pi' à la ligne 19 –

+0

@Rosarch: essayez maintenant. – Quassnoi

1

Poussé la condition de couleur dans la clause WHERE de sous-requêtes, en ajoutant la couleur au groupement et a ajouté DISTINCT pour soutenir un comportement identique de l'Union:

SELECT distinct Suppliers.sid 
    FROM Suppliers 
     inner JOIN (SELECT sid, color, COUNT(Parts.pid) AS partsPerSupplier 
        FROM Catalog 
        inner JOIN Parts on Catalog.pid = Parts.pid 
        WHERE Parts.color in ("red" , "green") 
        GROUP BY sid, color) AS partCounts 
      ON Suppliers.sid = partCounts.sid 
     inner JOIN (SELECT color, COUNT(pid) AS totalParts 
        FROM Parts 
        WHERE Parts.color in ("red", "green") 
        GROUP BY color) AS totalPartsTable 
      ON partCounts.color = totalPartsTable.color 
     AND totalPartsTable.totalParts = partCounts.partsPerSupplier 

Je ne sais pas que tous les SGBD disponibles pourraient être optimisés une version générique de ceci en poussant la condition "couleur" dans les sous-sélections, comme:

SELECT distinct Suppliers.sid 
    FROM Suppliers 
     inner JOIN (SELECT sid, color, COUNT(Parts.pid) AS partsPerSupplier 
        FROM Catalog 
        inner JOIN Parts on Catalog.pid = Parts.pid 
        GROUP BY sid, color) AS partCounts 
      ON Suppliers.sid = partCounts.sid 
     inner JOIN (SELECT color, COUNT(pid) AS totalParts 
        FROM Parts 
        GROUP BY color) AS totalPartsTable 
      ON partCounts.color = totalPartsTable.color 
     AND totalPartsTable.totalParts = partCounts.partsPerSupplier 
    WHERE color in ([some list of colors]) 
Questions connexes