按日期分组并组合3个表中的数据

时间:2014-06-05 01:01:46

标签: mysql group-by pivot case-statement

以下是我所拥有的三个表,其中session.id = signup.session_id和session.loc_id = location.id。最大覆盖是因为名称建议覆盖该位置的默认最大容量,因此IFNULL(session.max_override, location.max_cap)

mysql> SELECT * FROM session;
+----+---------------------+---------------+--------+
| id | date_time           | max_override  | loc_id |
+----+---------------------+---------------+--------+
| 1  | 2014-02-04 10:30:00 |      35       |    2   | 
| 2  | 2014-02-04 17:00:00 |               |    2   | 
| 3  | 2014-02-06 11:30:00 |      50       |    2   | 
| 4  | 2014-02-09 13:30:00 |               |    1   | 
+----+---------------------+---------------+--------+

mysql> SELECT * FROM location;
+-----------------+---------+
| id | location   | max_cap |
+-----------------+---------+
|  1 | up         | 20      |
|  2 | down       | 103     |
|  3 | right      | 50      |
|  4 | left       | 50      |
+-----------------+---------+

mysql> SELECT * FROM signups;
+-----------------+------------+
| id | name       | session_id |
+-----------------+------------+
|  1 | test       |    3       |
|  2 | admin      |    1       |
|  3 | meme       |    2       |
|  4 | anna       |    4       |
+-----------------+------------+

我试图创建的报告看起来很简单,但我不确定如何解决问题。以下是我希望报告/输出看起来像..

 mysql> query ouput;
+------------+----------+-----------+----------+----------+-----------+----------+
| date       | am_time  | am_ses_id | am_spots | pm_time  | pm_ses_id | pm_spots |
+------------+----------+-----------+----------+----------+-----------+----------+
| 2014-02-04 | 10:30 AM |    1      |    34    | 05:00 PM |     2     |    102   |
| 2014-02-06 | 11:30 AM |    3      |    49    |          |           |          |
| 2014-02-09 |          |           |          | 01:30 PM |     4     |    49    |
+------------+----------+-----------+----------+----------+-----------+----------+

我可以正确地对日期和时间进行分组,并设法使session_id匹配,因为它全部在一个表中但是要计算上午/下午点,这只是计算注册表中的记录特定会话并根据具体情况从max_capmax_override中扣除该值。

这就是我试过的

使用以下查询

SELECT 
    DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
    DATE_FORMAT(a.date_time,'%r') AS ses_time,
    a.id,
    COUNT(b.id) as signed_up,
    IFNULL(a.max_override,c.max_cap) AS cap
FROM
    test.session a
    LEFT JOIN
        test.signups b
        ON (b.session_id = a.id)
    LEFT JOIN
        test.location c
        ON (c.id = a.loc_id)
GROUP BY b.session_id

我得到以下输出

+------------+----------+--------+-----------+------+
| date       | ses_time | ses_id | signed_up | cap  |
+------------+----------+--------+-----------+------+
| 2014-02-04 | 10:30 AM |    1   |    1      |  35  |
| 2014-02-04 | 05:00 PM |    2   |    1      | 103  |
| 2014-02-06 | 10:30 AM |    3   |    1      |  50  |
| 2014-02-09 | 10:30 AM |    4   |    1      |  50  |
+------------+----------+--------+-----------+------+

但是我似乎无法找到一种方法只按日期对其进行分组,因此输出会显示为所需!我不知道我是否应该结合两个查询。

2 个答案:

答案 0 :(得分:1)

这是一种非常复杂的做法......

sqlfiddle:http://sqlfiddle.com/#!2/d85ca/11

select c.ses_date `date`, a.ses_time am_time, a.id am_ses_id, a.cap-a.signed_up am_spots, 
       b.ses_time pm_time, b.id pm_ses_id, b.cap-b.signed_up pm_spots
from (
    select distinct DATE_FORMAT(a.date_time,'%m/%d/%Y') ses_date
    from session a) c
left join (
    SELECT 
        DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
        DATE_FORMAT(a.date_time,'%r') AS ses_time,
        a.id,
        COUNT(b.id) as signed_up,
        IFNULL(a.max_override,c.max_cap) AS cap
    FROM
        session a
        LEFT JOIN
            signups b
            ON (b.session_id = a.id)
        LEFT JOIN
            location c
            ON (c.id = a.loc_id)
    where date_format(a.date_time, '%p') = 'AM'
    GROUP BY b.session_id) a on c.ses_date = a.ses_date
left join (
    SELECT 
        DATE_FORMAT(a.date_time,'%m/%d/%Y') AS ses_date,
        DATE_FORMAT(a.date_time,'%r') AS ses_time,
        a.id,
        COUNT(b.id) as signed_up,
        IFNULL(a.max_override,c.max_cap) AS cap
    FROM
        session a
        LEFT JOIN
            signups b
            ON (b.session_id = a.id)
        LEFT JOIN
            location c
            ON (c.id = a.loc_id)
    where date_format(a.date_time, '%p') = 'PM'
    GROUP BY b.session_id) b on c.ses_date = b.ses_date;

答案 1 :(得分:0)

您需要使用JOIN运算符让SQL DB知道表之间的关系。 在这种情况下,也可以更容易地执行子查询来获取计数(以避免GROUP BY)。我白天没有将AM和PM分开,但你可以这样做。

SELECT session.date_time,
    IFNULL(session.max_override,location.max_cap)-(
        SELECT COUNT(signups.id) 
        FROM signups 
        WHERE signups.session_id = session.id) as avail_spots
FROM session LEFT JOIN location ON session.loc_id = location.id;

请注意LEFT JOIN2014-02-04 17:00:00包含NULL avail_spots,因为max_override和max_cap都没有值,而INNER JOIN根本不会报告该会话。

fiddle

编辑:一旦您获得了白天的信息,您就可以在输出中使用它。试图隐藏时间但是在日期上进行分组会增加查询的复杂性,这可以通过用于UI的任何程序简单地解决。