It sounds like you are looking for a FULL [OUTER] JOIN
. Per documentation:
FULL OUTER JOIN
First, an inner join is performed. Then, for each row in T1 that does not satisfy the join condition with any row in T2, a joined row
is added with null values in columns of T2. Also, for each row of T2
that does not satisfy the join condition with any row in T1, a joined
row with null values in the columns of T1 is added.
SELECT *
FROM users u
JOIN user_products up ON u.id = up.user_id
AND u.id = 1
JOIN products p ON p.id = up.product_id
FULL JOIN categories c ON c.id = p.category_id;
This returns all categories and also returns all user-product combinations for the given user_id
.
If you are enforcing referential integrity with foreign keys and products.category_id
is defined NOT NULL
, so that every product is assigned to an existing category (not in your question), you can replace the FULL JOIN
with a RIGHT JOIN
.
Plus, either way, the condition to select a specific user has to move to a subquery or (simpler) to a JOIN
condition between the first three tables. It has to be applied before the last table categories
is joined.
SQL Fiddle.
I see it as 2 steps:
- Build tables with just the latest signal (or noise) for each device
JOIN
or UNION
the two tables.
Step 1 is a variant of groupwise max:
SELECT device_id, stats_time, status, noise -- The desired columns
FROM ( SELECT @prev := '' ) init
JOIN ( SELECT
device_id != @prev AS first, -- `device_id` is the 'GROUP BY'
@prev := device_id, -- the 'GROUP BY'
device_id, stats_time, status, noise -- Also the desired columns
FROM TableA -- The table
ORDER BY device_id DESC, -- The 'GROUP BY'
stats_time DESC -- to get latest
) x
WHERE first;
This may be beneficial to performance:
INDEX(device_id, stats_time)
Ditto for TableB
and signal
. Manually run them to see if I got them right.
Your example does not show a case where both signal
and noise
exist for the same device_id
. I will assume that is really the case, hence UNION
:
Step 2:
SELECT device_id, stats_time, status, signal, noise
FROM
( SELECT device_id, stats_time, status, signal, '' AS noise
... (the rest of the signal query)
)
UNION ALL
( SELECT device_id, stats_time, status, '' AS signal, noise
... (the rest of the noise query)
);
Best Answer
Please try: