简体   繁体   中英

MySQL Merge Table B into Table A based on values in row of Table B

I am trying to merge one table on another table based on a given value. But, it isn't as simple as a JOIN. ( I found plenty of JOIN examples online, but none like this. Also, I am not incredibly great at DB queries. )

For a simple example of what I am trying to accomplish, lets say I run a computer shop and sell multiple computers to multiple people. For whatever reason, these machines periodically check-in with me, and I want to know which customers of mine have a machine that is currently offline. However, if they have at least 1 machine online, I DO NOT want to see ANY of the machines they have that are either online OR offline.

My query so far is something like this:

SELECT * 
FROM Computers
LEFT JOIN Computers_On_Customers ON Computer_ID = Computers.ID
LEFT JOIN Customers ON Computers_On_Customers.Customer_ID = Customers.ID
WHERE Computers.Currently_Online LIKE "0"

However, if a Customer has 2 computers, one of each status, it will show 1 computer, when I want it to show neither. (Because one is currently offline, and therefore I do not care about the online one.) How could I go about this?

Here is a rough visual approximation of my database:

Customers:
ID     Other Stuff


Computers_On_Customers
ID     Customer_ID     Computer_ID

Computers:
ID     Currently_Online

Any help would be greatly appreciated.

You could use NOT EXISTS to filter out computers whose owners have a computer online:

SELECT * FROM Computers
    LEFT JOIN Computers_On_Customers ON Computer_ID = Computers.ID
    LEFT JOIN Customers ON Computers_On_Customers.Customer_ID = Customers.ID
WHERE 
    Computers.Currently_Online LIKE "0" AND 
    NOT EXISTS (
                SELECT 1 FROM Computers_On_Customers 
                    LEFT JOIN Computers ON Computer_ID = Computers.ID 
                    WHERE 
                        Currently_Online LIKE "1" AND
                        Computers_On_Customers.Customer_ID = Customers.ID
               )

You need to perform an aggregation and then take the result of that aggregation and select with the filters you want.

Using your example. Take the where and move it outside an aggregation selection.

SELECT 
    ID, offline_count
from
    (SELECT 
        Customers.ID,
            SUM(IF(Computers.Currently_Online Like '0', 0, 1)) 'offline_count'
    FROM
        Computers
    LEFT JOIN Computers_On_Customers ON Computer_ID = Computers.ID
    LEFT JOIN Customers ON Computers_On_Customers.Customer_ID = Customers.ID
    GROUP BY Customers.ID) c
where
    c.offline_count > 0

Assuming data_table has information to specify if a user is online or offline and there can be multiple entries. Aggregate the users and do sum of the offline count, if its > 0 after aggregating then you know that user has an offline entry. You can achieve similar with HAVING clause.

Assuming you just want the Customer data - surely you can just roll the whole thing up with a GROUP BY clause ... and since you're only after records where the maximum value of Computers.Currently_Online = 0 you should be able to use a MAX function to exclude anything where that value > 0.

SELECT Customers.*, MAX(Computers.Currently_Online) AS computer_online
FROM Customers

INNER JOIN Computers_On_Customers 
    ON Customers.ID = Computers_On_Customers.Customer_ID

INNER JOIN Computers
    ON Computers_On_Customers.Computer_ID = Computers.ID

GROUP BY Customers.ID

HAVING computer_online = 0

Personally I don't like nesting SELECTs unless I absolutely have to ... and in those instances I'd prefer to put it into a stored procedure.

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