2013-04-15 4 views
1

J'ai cinq tables de stockage des installations, les employés, les unités complétées, les projets et les équipes.Complexe MYSQL choisir parmi 5 tables

Je dois déterminer la productivité (nombre total d'heures complètes et cumulatives) d'un projet dans chaque installation, si l'installation a des heures d'ouverture de session sur le projet. L'installation est stockée dans la table des employés.

Voici ma structure de table, (réduite aux champs nécessaires à cette question):

facilities 
+------------+ 
| id   | 
+------------+ 
| label  | 
+------------+ 

employees 
+------------+ 
| id   | 
+------------+ 
| facility | 
+------------+ 

completes 
+------------+ 
| id   | 
+------------+ 
| project | 
+------------+ 
| completes | 
+------------+ 
| employee | 
+------------+ 

projects 
+------------+ 
| id   | 
+------------+ 
| title  | 
+------------+ 

shifts 
+------------+ 
| id   | 
+------------+ 
| project | 
+------------+ 
| length  | 
+------------+ 
| employee | 
+------------+ 

Là où je suis en cours d'exécution en difficulté est la sélection de la productivité pour une installation, lorsqu'il est stocké avec l'employé, non avec le décalage ou le nombre de finitions. Peut-être que c'est un défaut de conception? Est-ce que le tableau des changements et des remplacements devrait aussi contenir une colonne de service? Il semble redondant d'avoir une colonne de facilité, quand l'employé détermine déjà l'installation.

SELECT p.title, SUM(c.completes), SUM(s.length) 
FROM projects as p 
LEFT JOIN completes as c ON c.project = p.id 
LEFT JOIN shifts as s ON s.project = p.id 
GROUP BY p.id, shifts.employee.facility; 

Cette instruction GROUP BY n'est bien sûr pas valide. Mais cela démontre ce que je veux accomplir. Je voudrais également sélectionner l'étiquette de l'installation dans la déclaration. Comment puis-je aborder cela?

Merci d'avance pour toute idée que vous pouvez fournir!

Répondre

1

Ceci est l'un des rares cas où je trouverais un CROSS JOIN être la meilleure approche:

SELECT p.title, f.label, SUM(c.completes), SUM(s.length) 
FROM facilities as f   
CROSS JOIN projects as p 
JOIN employees as e ON f.id = e.facility 
LEFT JOIN completes as c ON c.employee = e.id AND c.project = p.id 
LEFT JOIN shifts as s ON s.employee = e.id AND s.project = p.id 
WHERE c.id IS NOT NULL OR s.id IS NOT NULL 
GROUP BY p.id, p.title, f.id, f.label 

Ce n'est pas en soi une mauvaise conception, mais il ne fait difficile que vous pouvez » t utilisez ici les relations parent-enfant typiques puisqu'il y a en réalité 2 parents sur vos tables completes et shifts.

Une approche alternative serait d'utiliser un UNION sans les jointures LEFT. Cela peut renvoyer un résultat plus rapide, en fonction du nombre de lignes actuellement dans vos facilities et projects tables:

SELECT p.title, 
     f.label, 
     SUM(CASE aggregated.type WHEN 'completes' THEN units ELSE 0 END), 
     SUM(CASE aggregated.type WHEN 'shifts' THEN units ELSE 0 END) 
FROM (
    SELECT 'completes' as type, project, employee, completes as units 
    FROM completes 
    UNION 
    SELECT 'shifts', project, employee, length 
    FROM shifts) aggregated 
JOIN projects as p ON aggregated.project = p.id 
JOIN employees as e ON aggregated.employee = e.id 
JOIN facilities as f ON e.facility = f.id 
GROUP BY p.id, p.title, f.id, f.label 

Comme vous pouvez le voir dans cette requête, le problème pourrait être résolu assez facilement si completes et shifts ont été stockés dans la même table. Cela peut ne pas fonctionner pour vous en fonction de vos besoins, mais cela peut être quelque chose à considérer comme un schéma alternatif.