MySQL - Grandchild category aggregation

时间:2016-07-11 21:22:54

标签: php mysql mysqli

I have following data hierarchy: Report > has many Modules > has many Instances.... each instance might have a different category assigned to it (finite but unknown amount of categories)

I need to produce a report level aggregate of instance categories... something like this:

| report_id | category  |       #     |
|         1 |         1 |           10|
|         1 |         2 |           5 | 
|         2 |         7 |           2 | 
|         2 |         4 |           14| 

I am new to MySQL and I have tried the following:

mysql> SELECT report_id.report_id, module_id.module_id, instance.instance_id, violation.name
-> FROM report_id
-> LEFT JOIN module_id
-> ON report_id.report_id=module_id.report_id
-> LEFT JOIN instance
-> ON module_id.module_id = instance.module_id
-> LEFT JOIN violation
-> ON instance.violation_id = violation.violation_id
-> ORDER BY report_id.report_id
-> ;

To produce:

+-----------+-----------+-------------+----------------+
| report_id | module_id | instance_id | category       |
+-----------+-----------+-------------+----------------+
|         1 |         1 |           1 | 1              |
|         1 |         2 |           5 | 1              |
|         1 |         1 |           2 | 2              |
|         1 |         1 |           3 | 3              |
|         1 |         1 |           4 | 3              |
|         1 |         3 |           6 | 3              |
|         2 |      NULL |        NULL | NULL           |
|         3 |      NULL |        NULL | NULL           |
+-----------+-----------+-------------+----------------+

I have also tried:

mysql> SELECT violation.name as Category, COUNT(instance.instance_id) AS NumberOfViolations FROM instance
-> LEFT JOIN violation
-> ON instance.violation_id=violation.violation_id
-> GROUP BY name;

+----------------+--------------------+
| Category       | NumberOfViolations |
+----------------+--------------------+
| 1              |                  2 |
| 2              |                  1 |
| 3              |                  3 |
+----------------+--------------------+

But this returns total category count for all the grandchildren. (now I need these totals separated by top level Report group)

I am having trouble finding the right syntax to marry these two queries to produce the table I show about. Any clues as to how to proceed would be helpful.

I do realized that I need someway to introduce SUM if (or count if) WHERE report's ID matched module's ID and module's ID matched instance ID but not sure how to incorporate this nested structure.

1 个答案:

答案 0 :(得分:0)

Thank you Marc B for making that comment about Grouping, that was the nudge that I needed.

This is what the resulting query looks like:

mysql> SELECT report_id.report_id, violation.name as Category, COUNT(instance.instance_id) AS NumberOfViolations FROM instance
-> LEFT JOIN violation
-> ON instance.violation_id=violation.violation_id
-> LEFT JOIN module_id
-> ON instance.module_id = module_id.module_id
-> LEFT JOIN report_id
-> ON module_id.report_id = report_id.report_id
-> GROUP BY report_id, violation.name;

Please note how I am still using module_id to join Instances (which hold violation_ids) to upper level report_ids but I am not using module_id as part of the SELECT statement so the output skips that column to just show my Report level category aggregation. Output below:

+-----------+----------------+--------------------+
| report_id | Category       | NumberOfViolations |
+-----------+----------------+--------------------+
|         1 | 1              |                  2 |
|         1 | 2              |                  1 |
|         1 | 3              |                  3 |
|         2 | 2              |                  10|
+-----------+----------------+--------------------+