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

PHP查询指定年月未提交付款用户数据问题求助

问题:获取指定年月未提交付款的用户信息

问题描述

我是PHP新手,开发项目时需要获取指定年月未提交付款的用户信息,现有代码无法正常运行,仅需展示该年月未付款的用户名,不知道如何实现IF/else逻辑,恳请帮助。

数据表信息

表名:credit
字段:usename(唯一)、month、Year

示例数据:

usenamemonthYear
ANovember2022
BNovember2022
BDecember2022

场景说明

用户A和B均在2022年11月提交过付款,2022年12月仅B提交了付款,需查询出用户A,期望输出:

usenamemonthYear
ANovember2022

现有前端表单代码

<form method="post" accept="" class="row g-3">
    <div class="col-lg-4">
        <label  for="val-select2">Month <span class="text-danger">*</span></label>
        <select  class="js-select2 form-select form-control" id="val-select2" name="pay_month" style="width: 100%;" required>
            <option value="<?php echo date("F")?>" hidden><?php echo date("F")?></option>
            <option value="January">January</option>
            <option value="February">February </option>
            <option value="March">March</option>
            <option value="April">April</option>
            <option value="May">May</option>
            <option value="June">June</option>
            <option value="July">July</option>
            <option value="August">August</option>
            <option value="September">September</option>
            <option value="October">October</option>
            <option value="November">November</option>
            <option value="December">December</option>
        </select>
    </div>
    <div class="col-lg-4">
        <label >Year<span class="text-danger">*</span></label>
        <input type="text" class="form-control"  name="pay_year" placeholder="year" required value="<?php echo date("Y");?>">
    </div>
    <div class="col-lg-2">
        <label></label>
        <button class="form-control btn btn-primary" name="save" type="submit"><i class="fa fa-eye" aria-hidden="true"></i> View</button>
    </div>
</form>

现有PHP查询代码

<?php
if (isset($_POST['save'])) {
    $sql = "SELECT * FROM credit WHERE  NOT (pay_month='" . $_POST['pay_month'] . "' AND  pay_year='" . $_POST['pay_year'] . "') ORDER BY username";
    if($result = mysqli_query($db, $sql)){
        if(mysqli_num_rows($result) > 0){
            $count = 0;
            while($row = mysqli_fetch_array($result)){
                if(mysqli_num_rows($result) > 0)
                    $count ++;
                echo '<tr id="'.$row["id"].'">';
                echo '<td class="fw-semibold">'.$count.'</td>';
                echo '<td class="fw-semibold fs-sm text-success"> <a href="single_info.php?name='.$row["usename"].'">'.$row["username"].'</a></td>';
                echo "</tr>";
            }
            mysqli_free_result($result);
        } else{
            echo "No data found.";
        }
    } else{
        echo "ERROR: Could not able to execute $sql. " . mysqli_error($db);
    }
}
?>

问题分析与解决方案

现有代码核心问题

  1. SQL逻辑错误:原查询NOT (pay_month='xxx' AND pay_year='xxx')会返回所有非指定年月的记录,比如用户A的11月记录、用户B的11月记录都会被返回,无法精准筛选出未在指定年月付款的用户。
  2. 字段名不匹配:数据表字段是usename、month、Year,但SQL中误用pay_month、pay_year,PHP输出中又错写username,导致数据无法正确读取。
  3. SQL注入风险:直接拼接用户输入到SQL语句,存在安全漏洞。

修正后的实现方案

1. 正确的SQL查询逻辑

要筛选出有付款记录但未在指定年月提交付款的用户,推荐使用子查询或左连接:

方式一:子查询实现
SELECT DISTINCT usename, month, Year 
FROM credit 
WHERE usename NOT IN (
    SELECT usename 
    FROM credit 
    WHERE month = ? AND Year = ?
)
ORDER BY usename

先找出指定年月已付款的用户,再从所有用户中排除这些人,返回他们的历史付款记录。

方式二:左连接实现
SELECT c.usename, c.month, c.Year
FROM credit c
LEFT JOIN credit c_paid 
    ON c.usename = c_paid.usename 
    AND c_paid.month = ? 
    AND c_paid.Year = ?
WHERE c_paid.usename IS NULL
GROUP BY c.usename
ORDER BY c.usename

通过左连接匹配指定年月的付款记录,筛选出无匹配结果的用户(即未付款用户)。

2. 优化后的PHP代码(带SQL注入防护)

<?php
if (isset($_POST['save'])) {
    // 获取表单输入
    $target_month = $_POST['pay_month'];
    $target_year = $_POST['pay_year'];

    // 使用预处理语句防止SQL注入
    $sql = "SELECT DISTINCT usename, month, Year 
            FROM credit 
            WHERE usename NOT IN (
                SELECT usename 
                FROM credit 
                WHERE month = ? AND Year = ?
            )
            ORDER BY usename";
    
    $stmt = mysqli_prepare($db, $sql);
    mysqli_stmt_bind_param($stmt, "ss", $target_month, $target_year);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);

    if(mysqli_num_rows($result) > 0){
        $count = 0;
        while($row = mysqli_fetch_assoc($result)){
            $count++;
            echo '<tr>';
            echo '<td class="fw-semibold">'.$count.'</td>';
            echo '<td class="fw-semibold fs-sm text-success"> 
                    <a href="single_info.php?name='.$row["usename"].'">'.$row["usename"].'</a>
                  </td>';
            // 可选:显示用户最后一次付款的年月
            echo '<td>'.$row["month"].'</td>';
            echo '<td>'.$row["Year"].'</td>';
            echo '</tr>';
        }
        mysqli_free_result($result);
    } else{
        echo "No data found.";
    }
    mysqli_stmt_close($stmt);
}
?>

关键说明

  • 字段名统一:确保代码中使用的字段名与数据表完全一致(usename、month、Year)。
  • 安全防护:必须使用预处理语句,避免直接拼接用户输入,杜绝SQL注入风险。
  • 逻辑精准:通过子查询或左连接,准确筛选出未在指定年月付款的用户,而非返回所有非目标年月的记录。

内容的提问来源于stack exchange,提问作者Shamim Hossain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:25:47