先用SELECT复刻WHERE条件查一遍,因UPDATE本身不返回要改的行(除非用RETURNING);PostgreSQL可用RETURNING获取修改后值,MySQL/SQL Server须在事务中分步执行并校验行数。

先用 SELECT 复刻 WHERE 条件查一遍
UPDATE 本身不返回要改的行(除非用 RETURNING),所以最直接、通用的做法就是把 UPDATE 的 WHERE 子句原样复制到 SELECT * 后面执行。比如你打算运行:
UPDATE users SET status = 'inactive' WHERE last_login < '2025-01-01' AND is_active = 1;
那就先跑:
SELECT * FROM users WHERE last_login < '2025-01-01' AND is_active = 1;
常见错误包括:
- 复制时漏括号,比如把
(a = 1 AND b = 2) OR c = 3写成a = 1 AND b = 2 OR c = 3,逻辑完全不同 - 在 UPDATE 里用了函数(如
UPPER(name)),但 SELECT 里没加,导致预览结果和实际影响行不一致 - 字段名含空格或关键字(如
order),SELECT 里没加反引号或双引号,直接报错
PostgreSQL 用户优先用 RETURNING
RETURNING 不是预览,而是带反馈的执行——它强制你真正改数据,但能立刻看到改完的结果。语句写法简单:
UPDATE users SET status = 'archived' WHERE id IN (101, 102, 103) RETURNING id, email, status;
但它不提供“修改前”的值。想对比前后?得用 CTE 配合子查询,例如:
WITH old AS (SELECT id, status FROM users WHERE id IN (101, 102, 103))<br>UPDATE users SET status = 'archived'<br>WHERE id IN (SELECT id FROM old)<br>RETURNING id, (SELECT status FROM old o WHERE o.id = users.id) AS old_status, status AS new_status;
注意:RETURNING 只在当前事务内有效,且无法跳过写入——它不能替代 SELECT 预览,而是补充验证手段。
MySQL / SQL Server 必须配事务分两步走
这两个系统不支持 RETURNING,只能靠事务保证 SELECT 和 UPDATE 之间数据不被并发修改。操作顺序必须是:
- 执行
BEGIN TRANSACTION(SQL Server)或START TRANSACTION(MySQL) - 跑预览查询:
SELECT id, name, updated_at FROM orders WHERE status = 'pending' - 确认无误后执行
UPDATE - 用
SELECT ROW_COUNT()(MySQL)或SELECT @@ROWCOUNT(SQL Server)检查实际影响行数 - 最后明确
COMMIT或ROLLBACK——漏掉这一步,锁会一直挂着
最容易被忽略的是:没开事务就直接 SELECT,中间别人改了数据,你 UPDATE 时实际影响范围已变。这不是理论风险,是线上高频事故点。
Navicat 里别指望“SQL预览”看 DML
Navicat 的“SQL预览”选项卡只反映结构变更(DDL),比如改字段类型、加索引生成的 ALTER TABLE 语句。它完全不显示你手动改数据网格后生成的 UPDATE 或 INSERT 语句。
真要看 DML,得盯住窗口底部状态栏——你在数据页双击改单元格、按 Ctrl+S 提交时,那里会实时弹出类似:
UPDATE `orders` SET `status` = 'shipped' WHERE `id` = 45678;
这个提示是 Navicat 自动生成的,不是你手写的;它只在提交瞬间出现,不保留、不可复制。想复核逻辑?还是得回到 SQL 编辑器里自己写 SELECT 验证。

















