简体   繁体   中英

Joining data from a table that is identified by another table

I have been asked to put together a small reporting system at work. We have a database where users commit information, namely a start and a stop time for various events.

The relevant tables of the DB: 在此处输入图片说明

As you can see, an event has a subcategory, and each subcategory belongs to a category.

I have been asked to produce a graph that represents the total amount of time events of a given category have occurred in a given date range.

So for example:

Category Name | Total time
**************************
Balloons      | 12h
Chalk         | 5.5h

I am struggling with getting a sum out of a join statement. As you can see, in order to map the total amounts of time to various categories, I have to first identify which subcategories belong to which categories, then organize the events accordingly.

I admit, I have been dead-set on writing this in one single query instead of writing a stored procedure or create temporary tables. I was convinced I could get it done with only joins, but it does not seem to be the case. I am completely open to any solution that works

One requirement; If a given category has no events, it should still appear in the results, only with a default value of 0.

This is what I have so far:

SELECT 
    event_categories.name,
    SUM(TIMESTAMPDIFF(MINUTE,
        events.start,
        events.stop) / 60) AS timeLost
FROM
    events
        LEFT JOIN
    event_subcategories ON event_subcategories.id = events.subcategory
        RIGHT JOIN
    event_categories ON event_categories.id = event_subcategories.id
WHERE
    events.date BETWEEN '2016-12-01' AND '2016-12-22'
        AND events.bed = 1
GROUP BY event_categories.id;

It almost works, producing a list of categories with the associated time lost. Only it doesn't display all of the categories, just the ones with events associated to them.

Change the way you do the joins. The main table should be event_categories . Assuming every category has subcategories, you can then use INNER JOIN with event_subcategories . Finally use LEFT JOIN with events , since some subcategories might not have any events.

You were also joining event_categories and event_subcategories on the wrong columns. It should be event_subcategories.category , not event_subcategory.id .

When you do a LEFT JOIN , any conditions on the child table should be in the ON clause, not WHERE . Because any category with no events will get NULL for all the event columns, so the conditions will never succeed for those rows and they would get filtered out as if you were doing INNER JOIN .

SELECT 
    c.name,
    SUM(TIMESTAMPDIFF(MINUTE,
        e.start,
        e.stop) / 60) AS timeLost
FROM event_categories AS c
JOIN event_subcategories AS s ON s.category = c.id
LEFT JOIN events AS e ON e.subcategory = s.id 
    AND e.date BETWEEN '2016-12-01' AND '2016-12-22'
    AND e.bed = 1
GROUP BY c.id;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM