如何检查同用户同日记录是否存在并实现条件插入数据
实现每日签到功能(避免重复记录)
这是个非常常见的日常签到场景需求,我一步步帮你落地实现:
1. 先搞定数据库表结构
首先你的签到表(比如命名为user_checkins)得有合适的字段和约束,核心是给userid和checkin_date加联合唯一索引——既能在数据库层面直接阻止重复插入,还能加快查询效率。
创建表的SQL示例:
CREATE TABLE user_checkins ( id INT AUTO_INCREMENT PRIMARY KEY, userid INT NOT NULL, companyid INT NOT NULL, checkin_date DATE NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 关键约束:同一用户同一天只能有一条签到记录 UNIQUE KEY unique_user_daily_checkin (userid, checkin_date) );
2. 写checkin.php的核心逻辑
这里有两种靠谱的实现方式,你可以根据需求选:
方式一:先查询再插入(直观易懂)
先检查当前用户今天有没有签到记录,没有就插入,否则返回提示。务必用预处理语句防SQL注入:
<?php // 假设你已经通过PDO建立了数据库连接 $pdo = new PDO('mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4', '用户名', '密码'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // 从会话获取当前用户和公司ID(登录后应该存在$_SESSION里) $userid = $_SESSION['user_id']; $companyid = $_SESSION['company_id']; $today = date('Y-m-d'); // 只取日期部分,确保按天判断签到 try { // 查询是否存在今日签到记录 $stmt = $pdo->prepare("SELECT id FROM user_checkins WHERE userid = ? AND checkin_date = ?"); $stmt->execute([$userid, $today]); $hasRecord = $stmt->rowCount() > 0; if ($hasRecord) { echo json_encode(['status' => 'error', 'message' => '记录已存在']); } else { // 插入新签到记录 $stmt = $pdo->prepare("INSERT INTO user_checkins (userid, companyid, checkin_date) VALUES (?, ?, ?)"); $stmt->execute([$userid, $companyid, $today]); echo json_encode(['status' => 'success', 'message' => '签到成功']); } } catch (PDOException $e) { echo json_encode(['status' => 'error', 'message' => '服务器出错:' . $e->getMessage()]); } ?>
方式二:利用数据库约束直接插入(更高效)
因为已经加了联合唯一索引,我们可以用INSERT IGNORE简化逻辑,不用提前查询,还能避免并发场景下的竞态问题:
<?php $pdo = new PDO('mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4', '用户名', '密码'); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $userid = $_SESSION['user_id']; $companyid = $_SESSION['company_id']; $today = date('Y-m-d'); try { // 用INSERT IGNORE:如果违反唯一约束,自动忽略插入操作 $stmt = $pdo->prepare("INSERT IGNORE INTO user_checkins (userid, companyid, checkin_date) VALUES (?, ?, ?)"); $stmt->execute([$userid, $companyid, $today]); if ($stmt->rowCount() > 0) { echo json_encode(['status' => 'success', 'message' => '签到成功']); } else { echo json_encode(['status' => 'error', 'message' => '记录已存在']); } } catch (PDOException $e) { echo json_encode(['status' => 'error', 'message' => '服务器出错:' . $e->getMessage()]); } ?>
3. 前端交互(给用户友好反馈)
用户点击签到按钮后,用AJAX请求后端并显示结果:
<button id="checkinBtn">点击签到</button> <div id="tipMessage"></div> <script> document.getElementById('checkinBtn').addEventListener('click', function() { const btn = this; btn.disabled = true; // 防止重复点击 fetch('checkin.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', } }) .then(res => res.json()) .then(data => { const tip = document.getElementById('tipMessage'); tip.textContent = data.message; // 给不同状态加样式区分 tip.style.color = data.status === 'success' ? 'green' : 'red'; btn.disabled = false; }) .catch(err => { document.getElementById('tipMessage').textContent = '请求失败,请重试'; document.getElementById('tipMessage').style.color = 'red'; btn.disabled = false; }); }); </script>
几个重要提醒
- 永远不要直接把
userid、companyid拼进SQL语句,预处理语句是防注入的基础。 - 日期处理要统一:要么用PHP的
date('Y-m-d'),要么用MySQL的CURDATE(),别带时间部分,不然同一用户同一天不同时间签到会被当成不同记录。 - 确保用户是已登录状态,避免未授权的恶意签到请求。
内容的提问来源于stack exchange,提问作者OWAIS ALI
相关产品推荐
相关产品推荐

