You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP+PostgreSQL环境下如何获取设备历史记录的上一任所有者信息

PHP+PostgreSQL环境下如何获取设备历史记录的上一任所有者信息

兄弟,我看你现在的需求是要从设备的历史流转记录里,拿到最后流转到仓库前的上一任所有者对吧?你现在用计数器的思路其实方向是对的,但其实可以从SQL层面或者PHP循环处理两个方向优化,给你理清楚两种好用的方案:


方案一:用PostgreSQL窗口函数直接获取(推荐,效率更高)

PostgreSQL自带的LAG()窗口函数可以直接在SQL查询里拿到同一设备的上一条历史记录的字段值,不用在PHP里绕来绕去做计数器,效率高很多。

先改写你的嵌套查询,直接把上一任所有者查出来:

SELECT 
    main.s_n,
    employers.employer AS current_owner,
    history.date AS current_date,
    -- 核心:拿到同一设备的上一条记录的所有者,也就是上一任
    LAG(employers.employer) OVER (PARTITION BY main.s_n ORDER BY history.date) AS prev_owner
FROM main
INNER JOIN history ON main.device_code = history.device_code
INNER JOIN employers ON employers.employer_code = history.employer_code
-- 按设备分组、日期排序,保证LAG拿到的是时间上的前一次记录
ORDER BY main.s_n, history.date DESC

关键参数解释:

  • PARTITION BY main.s_n:按设备序列号分组,确保只在同一设备的历史记录里找上一条
  • ORDER BY history.date:按日期正序排序,这样LAG()就能精准拿到时间上的上一次流转记录

然后PHP里的处理就简化太多了,而且还能避免原来的指针问题:

// 先查所有目标设备的基础信息
$result = pg_query($conn, "SELECT name,model,inventory_code,s_n,device_type_code FROM public.main WHERE device_type_code=1 ORDER BY main.s_n");
if (!$result) {
    echo "An error occurred.\n";
    exit;
}

// 注意!把整个表格的框架和表头提到循环外面,别每次循环都输出完整表格!
echo "<table class='styled-table'>
        <thead>
            <tr>
                <td>Equipment name</td>
                <td>Model</td>
                <td>ID</td>
                <td>Last date</td>
                <td>Current owner</td>
                <td>Previous owner</td>
            </tr>
        </thead>
        <tbody>";

// 遍历每个设备
while ($row = pg_fetch_row($result)) {
    $serial_number = $row[3];
    // 用改写后的SQL查该设备的历史记录,只取最新的一条(因为我们要最后流转到仓库的状态)
    $result2 = pg_query($conn, "
        SELECT 
            employers.employer AS current_owner,
            history.date AS current_date,
            LAG(employers.employer) OVER (PARTITION BY main.s_n ORDER BY history.date) AS prev_owner
        FROM main
        INNER JOIN history ON main.device_code = history.device_code
        INNER JOIN employers ON employers.employer_code = history.employer_code
        WHERE main.s_n = '$serial_number'
        ORDER BY history.date DESC
        LIMIT 1;
    ");

    if ($row2 = pg_fetch_assoc($result2)) {
        $last_date = $row2['current_date'];
        $last_owner = $row2['current_owner'];
        // 处理没有上一任的情况(比如设备刚入库,还没被租过)
        $prev_owner = $row2['prev_owner'] ?? "There were no transfers";

        // 只显示最后在仓库的设备
        if ($last_owner == "Warehouse") {
            echo "<tr>
                    <td>$row[0]</td>
                    <td>$row[1]</td>
                    <td>$row[2]</td>
                    <td>$last_date</td>
                    <td>$last_owner</td>
                    <td>$prev_owner</td>
                </tr>";
        }
    }
}

// 最后闭合表格
echo "</tbody></table>";

⚠️ 小提醒:最好用参数化查询避免SQL注入,比如用pg_prepare()和pg_execute(),别直接把$serial_number拼进SQL里。


方案二:改进你的PHP循环处理方法

如果不想改SQL,也可以在PHP里先把该设备的所有历史记录存到数组里,再遍历数组取上一条记录,这样比你原来的计数器方法更可靠(原来的方法里循环完$result2后,结果集指针已经到末尾,二次fetch可能拿不到数据):

$result = pg_query($conn, "SELECT name,model,inventory_code,s_n,device_type_code FROM public.main WHERE device_type_code=1 ORDER BY main.s_n");
if (!$result) {
    echo "An error occurred.\n";
    exit;
}

// 同样把表格框架放外面
echo "<table class='styled-table'>
        <thead>
            <tr>
                <td>Equipment name</td>
                <td>Model</td>
                <td>ID</td>
                <td>Last date</td>
                <td>Current owner</td>
                <td>Previous owner</td>
            </tr>
        </thead>
        <tbody>";

while ($row = pg_fetch_row($result)) {
    $serial_number = $row[3];
    // 查该设备的所有历史记录,按日期正序排序(最早的在前)
    $result2 = pg_query($conn, "
        SELECT employers.employer, history.date 
        FROM main 
        INNER JOIN history ON main.device_code = history.device_code
        INNER JOIN employers ON employers.employer_code = history.employer_code
        WHERE main.s_n = '$serial_number'
        ORDER BY history.date ASC;
    ");

    // 先把所有历史记录存到数组里,方便后续取值
    $history_records = [];
    while ($row2 = pg_fetch_assoc($result2)) {
        $history_records[] = $row2;
    }

    $total = count($history_records);
    if ($total == 0) continue; // 没有历史记录就跳过

    // 最新的记录是数组最后一个元素
    $last_record = end($history_records);
    $last_owner = $last_record['employer'];
    $last_date = $last_record['date'];

    if ($last_owner == "Warehouse") {
        // 上一任所有者:只有1条记录就显示无,否则取倒数第二个元素
        $prev_owner = $total == 1 ? "There were no transfers" : $history_records[$total - 2]['employer'];
        
        echo "<tr>
                <td>$row[0]</td>
                <td>$row[1]</td>
                <td>$row[2]</td>
                <td>$last_date</td>
                <td>$last_owner</td>
                <td>$prev_owner</td>
            </tr>";
    }
}

echo "</tbody></table>";

最后给你提个小bug修正

你原来的代码里每次循环都输出整个<table>标签,这样页面会生成N个独立的小表格,样式和体验都不好,一定要把<table>、<thead>放在循环外面,循环里只输出<tr>行,最后再闭合表格,这样才是一个完整的表格。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 13:18:00