简体   繁体   中英

MySQL PDO - latest row for table grouped with joins

I apologize for the title description as I wasn't sure how to best describe this.

There are multiple computers, multiple users per computer, and multiple data logs per user. I want to get the latest data log per computer.

I realize now that the query below does not provide the correct data because the ORDER BY happens for the results and the GROUP BY does so in no particular order.

I did read up on this before posting this and it appears a sub query is needed and then the result of that joined again on the same table to get the rest of that rows column values (the one found to be the latest). The examples I have found though are pretty basic and do not involve other tables being joined. It also seems I have to do this twice since I want it grouped by computer... (once for data_logs grouped by user_id and get the max then another grouped by computer_id to get the max of the earlier result) or maybe I am wrong there.

Need some help grasping how to tackle this and the approach to do so.

$stmt = $db->prepare("
    SELECT
        computers.computer_name,
        users.username,
        data_logs.window_title,
        data_logs.filename,
        data_logs.capture_timestamp
    FROM computers
    INNER JOIN users
        ON users.computer_id = computers.computer_id
    INNER JOIN data_logs
        ON data_logs.user_id = users.user_id AND data_logs.marked != 1
    WHERE computers.account_id = :cw_account_id AND computers.status = 1
    GROUP BY computers.computer_id
    ORDER BY data_logs.capture_timestamp desc
");

$binding = array('cw_account_id' => 1721);
$stmt->execute($binding);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo "<pre>";
print_r($results);
echo "</pre>";

One solution is to use a correlated subquery. The principle is that the outer query is not aggregated, but it has a condition in the WHERE clause that selects the latest log entry for the current computer id, using an aggregated subquery.

I guess that you would need this query (without seeing sample data and expected output though, this might not be 100% accurate) :

SELECT
    computers.computer_name,
    users.username,
    data_logs.window_title,
    data_logs.filename,
    data_logs.capture_timestamp
FROM computers
INNER JOIN users
    ON users.computer_id = computers.computer_id
INNER JOIN data_logs
    ON data_logs.user_id = users.user_id AND data_logs.marked != 1
WHERE 
    computers.account_id = :cw_account_id 
    AND computers.status = 1
    AND data_logs.capture_timestamp = (
        SELECT MAX(d.capture_timestamp)
        FROM computers c
                INNER JOIN users u ON u.computer_id = c.computer_id
        INNER JOIN data_logs d ON d.user_id = u.user_id AND d.marked != 1
        WHERE c.computer_id = computers.computer_id AND c.account_id = computers.account_id
    )
ORDER BY data_logs.capture_timestamp desc

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