开发者

MySQL grouping by date range with multiple joins

I currently have quite a messy query, which joins data from multiple tables involving two subqueries. I now have a requirement to group this data by DAY(), WEEK(), MONTH(), and QUARTER().

I have three tables: days, qos and employees. An employee is self-explanatory, a day is a summary of an employee's performance on a given day, and qos is a random quality inspection, which can be performed many times a day.

At the moment, I am selecting all employees, and LEFT JOINing day and qos, which works well. However, now, I need to group the data in order to breakdown a team or individual's performance over a date range.

Taking this data:

Employee

id  | name
------------------
1   | Bob Smith

Day

id  | employee_id  | day_date   | calls_taken
---------------------------------------------
1   | 1            | 2011-03-01 | 41
2   | 1            | 2011-03-02 | 24
3   | 1            | 2011-04-01 | 35

Qos

id   | employee_id  | qos_date   | score
----------------------------------------
1    | 1            | 2011-03-03 | 85
2    | 1            | 2011-03-03 | 95
3    | 1            | 2011-04-01 | 91

If I were to start by grouping by DAY(), I would need to see the following results:

Day__date  | Day__Employee__id | Day__calls | Day__qos_score
------------------------------------------------------------
2011-03-01 | 1                 | 41         | NULL
2011-03-02 | 1                 | 24         | NULL
2011-03-03 | 1                 | NULL       | 90
2011-04-01 | 1                 | 35         | 91

As you see, Day__calls should be SUM(calls_taken) and Day__qos_score is AVG(score). I've tried using a similar method as above, but as the date isn't known until one of the tables has been joined, its only displaying a record where there's a day saved.

Is there any way of doing this, or am I going about things the wrong way?

Edit: As requested, here's what I've come up with so far. However, it only shows dates where there's a day.

SELECT COALESCE(`day`.day_date, qos.qos_date)      AS Day__date,
      employee.id                                  AS Day__Employee__id,
      `day`.calls_taken                            AS Day__Day__calls,
      qos.score                                    AS Day__Qos__score
FROM   faults_employees `employee`
      LEFT JOIN (SELECT `day`.employee_id                    AS employee_id,
                        SUM(`day`.calls_taken)               AS `calls_in`,
                 FROM   faults_days AS `day`
                 WHERE employee.id = 7
                 GROUP  BY (`day`.day_date)
        ) AS `day`
        ON `day`.开发者_开发问答employee_id = `employee`.id
      LEFT JOIN (SELECT `qos`.employee_id AS employee_id,
                        AVG(qos.score)   AS `score`
                 FROM   faults_qos qos
                 WHERE employee.id = 7
                 GROUP  BY (qos.qos_date)
        ) AS `qos`
        ON `qos`.employee_id = `employee`.id AND `qos`.qos_date = `day`.day_date
WHERE employee.id = 7
GROUP  BY Day__date
ORDER BY `day`.day_date ASC


The solution I'm comming up with looks like:

SELECT
    `date`,
    `employee_id`,
    SUM(`union`.`calls_taken`) AS `calls_taken`,
    AVG(`union`.`score`) AS `score`
FROM ( -- select from union table
    (SELECT -- first select all calls taken, leaving qos_score null
        `day`.`day_date` AS `date`,
        `day`.`employee_id`,
        `day`.`calls_taken`,
        NULL AS `score`
    FROM `employee`
    LEFT JOIN
        `day`
            ON `day`.`employee_id` = `employee`.`id`
    )
    UNION -- union both tables
    (
    SELECT -- now select qos score, leaving calls taken null
        `qos`.`qos_date` AS `date`,
        `qos`.`employee_id`,
        NULL AS `calls_taken`,
        `qos`.`score`
    FROM `employee`
    LEFT JOIN
        `qos`
            ON `qos`.`employee_id` = `employee`.`id`
    )
) `union`
GROUP BY `union`.`date` -- group union table by date

For the UNION to work, we have to set the qos_score field in the day table and the calls_taken field in the qos table to null. If we don't, both calls_taken and score would be selected into the same column by the UNION statement. After this, I selected the required fields with the aggregation functions SUM() and AVG() from the union'd table, grouping by the date field in the union table.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜