求助:获取指定交易类型的员工最新交易详情实现方案
问题:获取员工指定类型的最新交易详情
需求说明
要获取所有员工中,交易类型为Add、Update、Read的最新交易详情,注意:如果员工最后一笔交易是Delete(不在指定范围内),则不纳入结果。
样例数据表
employees表
| employee_id | employee_name |
|---|---|
| 1 | John Doe |
| 2 | Jane Doe |
| 3 | Teri Dactyl |
| 4 | Allie Grater |
transactions表
| transaction_id | employee_id | transaction_date | transaction_type | remarks |
|---|---|---|---|---|
| 1 | 1 | 2021-03-28 | Add | test 1 |
| 2 | 3 | 2022-09-07 | Add | test 2 |
| 3 | 2 | 2019-08-01 | Add | test 3 |
| 4 | 4 | 2023-06-05 | Read | test 4 |
| 5 | 4 | 2023-05-12 | Add | test 5 |
| 6 | 2 | 2020-02-01 | Read | test 6 |
| 7 | 3 | 2022-11-15 | Update | test 7 |
| 8 | 1 | 2020-06-14 | Add | test 8 |
| 9 | 1 | 2020-01-14 | Update | test 9 |
| 10 | 2 | 2023-12-31 | Delete | test 10 |
期望输出
| Transaction ID | Employee Name | Transaction Date | Transaction Type | Remarks |
|---|---|---|---|---|
| 4 | Allie Grater | 2023-06-05 | Read | test 4 |
| 7 | Teri Dactyl | 2022-11-15 | Update | test 7 |
| 1 | John Doe | 2021-03-28 | Add | test 1 |
注:Jane Doe不在结果中,因其最后一笔交易类型为Delete,不属于指定的[Add, Update, Read]范围。
当前代码(PHP)
<?php $transaction_types = ['Add', 'Update', 'Read']; $output = ''; $query = "SELECT * FROM transactions INNER JOIN employees ON employees.employee_id = transactions.employee_id WHERE transactions.transaction_type IN ('".implode("', '", $transaction_types)."') GROUP BY transactions.employee_id ORDER BY DATE(transactions.transaction_date) DESC "; $stmt = $connect->prepare($query); if ($stmt->execute()) { if ($stmt->rowCount() > 0) { $output .= '<table> <thead> <tr> <th>Transaction ID</th> <th>Employee Name</th> <th>Transaction Date</th> <th>Transaction Type</th> <th>Remarks</th> </tr> </thead> <tbody>'; $result = $stmt->fetchAll(); foreach ($result as $row) { $output .= '<tr> <td>'.$row->transaction_id.'</td> <td>'.$row->employee_name.'</td> <td>'.$row->transaction_date.'</td> <td>'.$row->transaction_type.'</td> <td>'.$row->remarks.'</td> </tr>'; } $output .= '</tbody></table>'; } } echo $output; ?>
问题分析与修正方案
当前代码的SQL存在两个核心问题:
- GROUP BY逻辑错误:直接按
employee_id分组后,SELECT *会返回每组的第一条数据(而非最新交易),不符合需求。 - 未过滤最后一笔交易为Delete的员工:当前WHERE条件只筛选了指定类型的交易,但员工可能有后续的Delete交易,这类员工应该被排除。
修正后的SQL逻辑
先找出每个员工的最新交易日期,判断该交易是否属于指定类型;如果是,再关联获取该交易的详情。
修正后的SQL语句:
SELECT t.transaction_id, e.employee_name, t.transaction_date, t.transaction_type, t.remarks FROM transactions t INNER JOIN employees e ON e.employee_id = t.employee_id INNER JOIN ( -- 子查询获取每个员工的最新交易日期 SELECT employee_id, MAX(transaction_date) AS latest_date FROM transactions GROUP BY employee_id ) latest_t ON t.employee_id = latest_t.employee_id AND t.transaction_date = latest_t.latest_date -- 只保留最新交易属于指定类型的记录 WHERE t.transaction_type IN ('Add', 'Update', 'Read') ORDER BY t.transaction_date DESC;
修正后的PHP代码
<?php $transaction_types = ['Add', 'Update', 'Read']; $output = ''; // 使用参数绑定避免SQL注入 $query = "SELECT t.transaction_id, e.employee_name, t.transaction_date, t.transaction_type, t.remarks FROM transactions t INNER JOIN employees e ON e.employee_id = t.employee_id INNER JOIN ( SELECT employee_id, MAX(transaction_date) AS latest_date FROM transactions GROUP BY employee_id ) latest_t ON t.employee_id = latest_t.employee_id AND t.transaction_date = latest_t.latest_date WHERE t.transaction_type IN (:types) ORDER BY t.transaction_date DESC"; // 处理数组参数绑定,适配PDO $typesStr = implode(',', array_fill(0, count($transaction_types), '?')); $query = str_replace(':types', $typesStr, $query); $stmt = $connect->prepare($query); $stmt->execute($transaction_types); if ($stmt->rowCount() > 0) { $output .= '<table> <thead> <tr> <th>Transaction ID</th> <th>Employee Name</th> <th>Transaction Date</th> <th>Transaction Type</th> <th>Remarks</th> </tr> </thead> <tbody>'; $result = $stmt->fetchAll(PDO::FETCH_OBJ); foreach ($result as $row) { $output .= '<tr> <td>'.$row->transaction_id.'</td> <td>'.$row->employee_name.'</td> <td>'.$row->transaction_date.'</td> <td>'.$row->transaction_type.'</td> <td>'.$row->remarks.'</td> </tr>'; } $output .= '</tbody></table>'; } echo $output; ?>
关键改进点
- 用子查询先获取每个员工的最新交易日期,确保只筛选该日期的交易;
- 通过WHERE条件排除最新交易为Delete的员工;
- 使用参数绑定避免SQL注入风险(原代码直接拼接字符串存在注入隐患);
- 明确指定SELECT字段,避免GROUP BY或JOIN时的字段冲突。
内容的提问来源于stack exchange,提问作者Mr.Jepoyyy
相关产品推荐
相关产品推荐

