2010-02-21 6 views
1

Voici une requête MySQL Je suis en cours d'exécution:Garder SQL à sec

-- get the sid of every supplier who does not supply both a red and green part 
SELECT Suppliers.sid, Parts.color 
FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid 
WHERE Suppliers.sid NOT IN (
    SELECT Suppliers.sid 
    FROM Suppliers 
    JOIN Catalog ON Catalog.sid = Suppliers.sid 
    JOIN Parts ON Parts.pid = Catalog.pid 
    WHERE Parts.color IN ('red', 'green') 
    GROUP BY Suppliers.sid 
    HAVING COUNT(DISTINCT Parts.color) = 2 
) 
ORDER BY Suppliers.sid DESC; 

Comme vous pouvez le voir, cela se répète deux fois:

FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid 

Que puis-je faire pour ne déclarer cette fois, et le référencer deux fois? Ou est-ce un signe que toute ma requête est imparfaite en quelque sorte?

Le problème est exacerbé lorsque j'ai 15 requêtes différentes que je cours avec ces mêmes trois lignes.

Répondre

5

Si vous voulez continuer à utiliser une relation de tables ensemble dans votre système, alors vous voulez regarder dans view.

+1

Une vue permet de résoudre le problème de SQL répété, comme indiqué par Scwagner. Il fournit également un niveau d'abstraction utile entre le stockage de la table physique et l'apparence logique des données dans votre application. –

+0

Mais attention, une vue peut vous mordre dans le cul si vous l'utilisez trop, surtout quand la vue retourne plus de colonnes que vous n'en avez besoin dans votre cas particulier ou fait beaucoup de jointures inutiles. Si vous êtes après des performances simples, il vous suffit de sécher – CResults

0

Une solution plus ANSI Je suppose travaillerait en MySQL:

SELECT X.sid, X.color 
    FROM (SELECT Catalog.sid, parts.color, 
       count(distinct parts.color) as distinct_color_count 
      from Catalog 
       inner jOIN Parts 
        ON Parts.pid = Catalog.pid 
     where parts.color in ("red", "green") 
     group by catalog.sid, parts.color) 
     ) x 
where x.distinct_color_count = 2 
order by x.sid desc 

Vous ne tirez rien de fournisseurs, mais sid, et qui doit exister dans le catalogue, utilisez donc Catalog.sid à la place.

Activez l'instruction select afin d'obtenir le paramètre distinct_color_count afin que vous puissiez le filtrer à l'étape suivante. Si vous essayez ceci:

SELECT Catalog.sid, parts.color, 
     count(distinct parts.color) 
    from Catalog 
     inner join Parts 
      ON Parts.pid = Catalog.pid 
where parts.color in ("red", "green") 
having count(distinct parts.color) = 2 
group by catalog.sid, parts.color 
order by catalog.sid ; 

cela ne fonctionnera pas, car chaque ligne n'aura qu'une seule couleur distincte.

0

Vous pouvez tarir les requêtes les plus courantes (en particulier commune rejoint) avec une vue comme celle-ci:

CREATE OR REPLACE ALGORITHM=MERGE VIEW Suppliers_Catalog_Parts 
AS 
select * 
FROM Suppliers 
JOIN Catalog ON Catalog.sid = Suppliers.sid 
JOIN Parts ON Parts.pid = Catalog.pid; 

Vous pouvez modifier * à des colonnes spécifiques pour éviter les conflits de noms id.

Il y a quelques astuces à connaître. Tout d'abord, pour les vues sans clause where, spécifiez TOUJOURS l'algorithme comme MERGE afin que la vue soit stockée en tant que requête, puis fusionnée avec votre SQL au moment de l'exécution; sinon, il peut être évalué comme une table temporaire (ce qui peut potentiellement être désastreux pour des vues génériques comme celle-ci).

Deuxièmement, certaines requêtes ne peuvent pas être créées en tant que VIEW - en particulier si la clause from contient une sous-requête. Il existe des solutions de contournement pour cela aussi.

Si vous voulez en savoir plus, je vous écris une série sur la façon d'écrire DRY SQL ici: http://blog.gruffdavies.com/2014/08/23/how-to-write-dry-sql-in-mysql-part-1-views/

HTH

Gruff

Questions connexes