2013-09-04 3 views
0

J'essaie de déterminer si la requête que je souhaite effectuer est réalisable ou réalisable en SQL ou si j'ai besoin de collecter des données brutes et de les traiter dans mon application .Collecte de plusieurs colonnes de données agrégées avec une jointure

Mon schéma ressemble à ceci:

applications 
================ 
id INT 

application_steps 
================= 
id INT 
application_id INT 
step_id INT 
activated_at DATE 
completed_at DATE 

steps 
===== 
id INT 
step_type_id INT 

Idéalement, ces données dans application_steps:

| id | application_id | step_id | activated_at | completed_at | 
| 1 | 1    | 1  | 2013-01-01 | 2013-01-02 | 
| 2 | 1    | 2  | 2013-01-02 | 2013-01-02 | 
| 3 | 1    | 3  | 2013-01-02 | 2013-01-10 | 
| 4 | 1    | 4  | 2013-01-10 | 2013-01-11 | 
| 5 | 2    | 1  | 2013-02-02 | 2013-02-02 | 
| 6 | 2    | 2  | 2013-02-02 | 2013-02-07 | 
| 7 | 2    | 4  | 2013-02-09 | 2013-02-11 | 

Je veux obtenir ce résultat:

| application_id | step_1_days | step_2_days | step_3_days | step_4_days | 
| 1    | 1   | 0   | 8   | 1   | 
| 2    | 0   | 5   | NULL  | 2   | 

Notez que dans la réalité il y a beaucoup d'autres étapes et beaucoup d'autres applications que je pourrais envisager.

Comme vous pouvez le voir, il existe un has-many relation entre applications et application_steps. Il est également possible qu'une étape donnée ne soit pas utilisée pour une application particulière. Je voudrais obtenir la quantité de temps que chaque étape prend (en utilisant DATEDIFF(completed_at, activated_at)), tous en une seule ligne (les noms de colonnes n'ont pas d'importance). Est-ce possible?

question secondaire: Pour compliquer les choses un peu plus loin, je vais aussi avoir besoin d'une requête secondaire qui rejoint application_steps avec steps et obtient seulement des données pour les étapes avec un step_type_id particulier. En supposant que la première partie est possible, comment puis-je l'étendre pour filtrer efficacement?

REMARQUE: L'efficacité est la clé ici - c'est un rapport annuel, ce qui équivaut à environ 2500 applications avec 70 différents steps et 44000 application_steps dans la production (pas beaucoup de données, mais potentiellement beaucoup quand les jointures sont pris en compte) .

+0

[peut-être cela vous aidera] (http://stackoverflow.com/a/16298859/319542). – Lobo

Répondre

1

Cela devrait être une agrégation « pivotante » base:

select id, 
     max(case when step_id = 1 then datediff(completed_at, activated_at) end) as step_1_days, 
     max(case when step_id = 2 then datediff(completed_at, activated_at) end) as step_2_days, 
     max(case when step_id = 3 then datediff(completed_at, activated_at) end) as step_3_days, 
     max(case when step_id = 4 then datediff(completed_at, activated_at) end) as step_4_days 
from application_steps s 
group by id; 

vous devez répéter cette opération pour les 70 étapes.

Pour ce faire que pour un type particulier de l'étape:

select application_id, 
     max(case when step_id = 1 then datediff(completed_at, activated_at) end) as step_1_days, 
     max(case when step_id = 2 then datediff(completed_at, activated_at) end) as step_2_days, 
     max(case when step_id = 3 then datediff(completed_at, activated_at) end) as step_3_days, 
     max(case when step_id = 4 then datediff(completed_at, activated_at) end) as step_4_days 
from application_steps s join 
    steps 
    on s.step_id = steps.id and 
     steps.step_type_id = XXX 
group by application_id; 
+0

devrait-il que 'max' soit' sum'? – Lobo

+0

[violon sql] (http://sqlfiddle.com/#!2/7639b/1) – Lobo

+0

@Lobo. . . Je ne sais pas si cela devrait être 'max()' ou 'sum()', et cela ne fera peut-être pas de différence. Ce qui dépend des données et des besoins de l'entreprise. Quand il n'y a qu'une seule valeur attendue par colonne pivot, j'utilise habituellement 'max()'. –

Questions connexes