SQL语法咨询:如何优先从表B取数,不存在则取表A数据?
你说得没错,直接在CASE里用a.*或者b.*确实走不通——CASE表达式只能返回单个值,没法直接返回整行数据。这里给你两个实用的实现方案,根据你的表结构复杂度选就行:
方案1:逐列用COALESCE映射(适合列数少的场景)
因为两张表的列数、结构完全一致,我们可以对每一列使用COALESCE()函数——它会返回传入参数里第一个非NULL的值。这样就能完美实现「优先取B表数据,B表没有就取A表对应列」的需求。
示例代码:
SELECT COALESCE(b.id, a.id) AS id, COALESCE(b.column_2, a.column_2) AS column_2, COALESCE(b.column_3, a.column_3) AS column_3, -- 把所有列都按这个格式列出来 COALESCE(b.column_n, a.column_n) AS column_n FROM A a LEFT JOIN B b ON b.id = a.id;
这个方法逻辑直白,容易理解,但如果表的列特别多,手动写每一列会有点繁琐。
方案2:用UNION ALL合并结果(适合列数多的场景)
如果表的列很多,不想逐列敲代码,用UNION ALL会更高效:先取出B表的所有数据,再取出A表中那些ID不在B表里的数据,最后把两部分结果合并起来。
基础版代码:
-- 先取B表的全部数据 SELECT * FROM B UNION ALL -- 再取A表中未出现在B表的行 SELECT * FROM A WHERE id NOT IN (SELECT id FROM B);
要是B表的id列可能存在NULL值,上面的NOT IN会出问题,换成NOT EXISTS更安全:
SELECT * FROM B UNION ALL SELECT * FROM A a WHERE NOT EXISTS (SELECT 1 FROM B b WHERE b.id = a.id);
这个方法不用写所有列名,只要两张表的列顺序、数据类型完全匹配就行,非常省心。
补充:为什么你原来的写法不对?
CASE WHEN b.id IS NULL THEN a.* ELSE b.* END这种写法不符合SQL语法规范——CASE表达式要求所有分支返回的数据类型、结构必须一致,而且它只能返回单个列值,没法直接返回整行的结果集,所以执行时会直接报错。
内容的提问来源于stack exchange,提问作者Patan
相关产品推荐
相关产品推荐

