跨库子查询必须显式写全限定名,否则直接报错;mysql报unknown database,postgresql报relation does not exist,sql server报invalid object name;正确写法需按数据库规范补全路径,如mysql用db2.logs,postgresql用db2.public.logs,sql server用[otherserver].[db2].[dbo].[logs]。

跨库子查询必须显式写全限定名,否则直接报错
不加库名前缀的 SELECT * FROM users WHERE id IN (SELECT user_id FROM logs) 在任何主流数据库里都会失败。MySQL 报 Unknown database 'logs',PostgreSQL 报 relation "logs" does not exist,SQL Server 报 Invalid object name 'logs'。这不是语法警告,是硬性拦截。
正确做法是按数据库规范补全路径:
- MySQL:
db2.logs(不带 schema) - PostgreSQL:
db2.public.logs(public不能省,且数据库名本身不参与解析,实际靠dblink或postgres_fdw映射) - SQL Server:
[OtherServer].[db2].[dbo].[logs](四段式,链接服务器名必须已存在)
漏掉任意一级,语句根本进不了优化器,更别说执行。
别用 NOT IN 做主键存在性校验,NULL 会静默丢数据
WHERE id NOT IN (SELECT id FROM db2.users) 看似直白,但只要子查询返回任意一个 NULL,整行就被判为 UNKNOWN,最终过滤掉——不是查不到,是 SQL 三值逻辑把它“吃”了。线上核对时这会导致差异数归零,误判一致性。
改用 NOT EXISTS 才可靠:
SELECT id, email FROM db1.users u WHERE NOT EXISTS ( SELECT 1 FROM db2.users v WHERE v.id = u.id );
关键点:
- 子查询里固定写
SELECT 1,不传冗余字段 -
v.id = u.id的等值条件必须有索引支撑,否则每次外层行都触发远端全表扫 - 如果 db2 是 PostgreSQL,确认
postgres_fdw开启了pushdown,否则子查询会在本地拉全量再过滤
字段级比对必须处理空值、聚合粒度和浮点容差
直接比 (SELECT SUM(amount) FROM db1.sales) = (SELECT SUM(amount) FROM db2.sales) 极易崩:任一库无记录,SUM() 返回 NULL,整个表达式为 NULL,条件失效。
安全写法要三层对齐:
- 空值转 0:
COALESCE(SUM(amount), 0) - 聚合维度一致:若 db1 是明细表、db2 是按天汇总,则子查询必须
GROUP BY date,否则一对多导致重复累加 - 浮点防精度误差:
ABS(a - b) 替代 <code>a = b,尤其金额、权重类字段
注意:某些数据库(如旧版 MySQL)不支持在子查询中直接用 LIMIT,像 (SELECT id FROM db2.logs ORDER BY ts DESC LIMIT 100) 会报语法错误,得改用派生表或窗口函数。
子查询嵌套在 UPDATE/INSERT 中时,MySQL 和 PostgreSQL 行为完全不同
想把 db1 订单状态同步到 db2 客户表,MySQL 只能走 INSERT INTO db2.customers SELECT ... FROM db1.orders 或 UPDATE t1 JOIN t2;它不支持 UPDATE ... SET col = (SELECT ...) 引用跨库表,会报 You can't specify target table for update in FROM clause。
PostgreSQL 则可用标准 UPDATE ... FROM:
UPDATE db2.customers c SET status = o.status FROM db1.orders o WHERE c.order_id = o.id;
但要注意:
- WHERE 条件必须写在末尾,漏掉就全表更新成同一值
- 若
o.id不唯一,PostgreSQL 默认取任意匹配行,需提前用DISTINCT ON或子查询去重 - 执行前务必
EXPLAIN,确认db1.orders(order_id)有索引,否则变成嵌套循环 + 远端全表扫
真正容易被忽略的是权限链:你得同时有 db1 的 SELECT 和 db2 的 UPDATE 权限,而 PostgreSQL 的 postgres_fdw 还要求远端用户具备对应表的 SELECT 权限——少一层,运行时报错,不是建语句时报错。










