PostgreSQL中关联多表时无需显式枚举所有字段查询全部内容并合并重复字段的实现方法
哥们我太懂你这种痛点了!当表A和表B都堆着上百个字段时,手动敲完所有字段名不仅工作量拉满,还容易漏写、写错,简直是开发者的噩梦。刚好PostgreSQL里有几个实用的办法,能帮你不用一个个枚举字段,还能自动合并重复的关联字段,直接实现你要的效果!
最省心的方案:USING子句 + SELECT *
这绝对是PostgreSQL给咱们偷懒的福利,完美匹配你的需求!
当两个表有共同的关联字段(比如id)时,用USING子句来关联,再配合SELECT *,PostgreSQL会自动帮你做两件事:
- 查出表A的所有字段 + 表B中除了关联字段之外的所有字段
- 把重复的关联字段(比如
id)合并成一列,不会出现两个id列
直接上代码示例,这就是你要的替代方案:
SELECT * FROM a LEFT JOIN b USING (id);
对比你之前的select a.*, b.x1, b.x2, b.x3......,这个代码简洁到飞起!而且完全实现了“查所有字段+合并重复关联字段”的需求,根本不用手动列那些b.x1、b.x2...
如果有多个共同关联字段也一样,比如id和created_at都是两个表的共同关联字段,只要把它们都放进USING里:
SELECT * FROM a LEFT JOIN b USING (id, created_at);
这时候id和created_at都会被合并,只各出现一次,其他字段全部自动包含进来。
特殊场景:用ON关联时的处理方案
如果你因为某些原因必须用ON子句来关联(比如关联条件不是简单的字段相等),那也可以用PostgreSQL 12及以上版本支持的EXCLUDE语法来排除重复字段,比如:
SELECT a.*, (b.* EXCLUDE (id)) FROM a LEFT JOIN b ON a.id = b.id;
这里的b.* EXCLUDE (id)会取出b表中除了id之外的所有字段,配合a.*就实现了和上面USING一样的效果,合并了重复的id字段。
如果要排除多个重复字段,直接在EXCLUDE里列出来就行:
SELECT a.*, (b.* EXCLUDE (id, created_at)) FROM a LEFT JOIN b ON a.id = b.id AND a.created_at = b.created_at;
给你提个醒:生产环境的小权衡
虽然SELECT *省了超多事,但我还是要啰嗦一句:在生产环境的应用代码里,尽量别随便用SELECT *。因为如果后面表结构变了(比如新增字段、调整字段顺序),查询结果的列顺序或者数量也会跟着变,可能导致应用程序报错。但如果是临时查询、调试数据或者快速导出内容,这个方法绝对是效率神器!
另外,如果两个表除了关联字段之外,还有其他同名但含义不同的字段(比如a表的name是用户名,b表的name是商品名),那SELECT *会把这两个name都查出来,结果里会有两个name列。这种情况你还是得手动给它们重命名(比如b.name AS product_name),不过这属于特殊场景,大部分时候用上面的方法都能解决你的问题。
备注:内容来源于stack exchange,提问作者dbcoffee

