如何实现update select 语句

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
简介: 如何实现update select 语句

前言:



有些时候我们会遇到如下情况,我们需要依赖一张表的查询结果来更新另一张表,比如我们存在一张主表和一张关联表,我们需要把关联表的部分字段数据同步到主表的里面。


这次的文章出现也是因为这样一个类似的需求,个人需要把一个30万行(后续会发文介绍常见的处理手段)的数据文件入库,同时需要将部分字段迁移到另一张表,两个表之间通过两个字段进行and匹配。下面画一下结构图:


网络异常,图片无法展示
|


处理方式也比较简单,直接使用sql就可以完成,这篇文章针对这个小需求,总结一下update select 的几种实现方式。


文章目的:



  1. 实现update select 的几种常见方法
  1. join
  2. merge
  3. 子查询
  1. merge的踩坑和问题


准备数据



为了更好的进行实际操作,这里构建两张简单的表来模拟场景。直接复制下面的db即可,由于不同数据库sql不同,这里使用的是postgreSql 数据库。


旧表


CREATE TABLE "public"."olddb" (
  "id" int4 NOT NULL,
  "relevance1" varchar(255) COLLATE "pg_catalog"."default",
  "relevance2" varchar(255) COLLATE "pg_catalog"."default",
  "new_field" varchar(255) COLLATE "pg_catalog"."default",
  CONSTRAINT "olddb_pkey" PRIMARY KEY ("id")
)
;
ALTER TABLE "public"."olddb" 
  OWNER TO "postgres";
COMMENT ON COLUMN "public"."olddb"."id" IS '主键';
COMMENT ON COLUMN "public"."olddb"."relevance1" IS '关联字段1';
COMMENT ON COLUMN "public"."olddb"."relevance2" IS '关联字段2';
COMMENT ON COLUMN "public"."olddb"."new_field" IS '新字段,需要由关联表同步';
复制代码


表成功创建之后,在内部加入一些简单的数据:


网络异常,图片无法展示
|


新表


CREATE TABLE "public"."newdb" (
  "id" int4 NOT NULL,
  "relevance1" varchar(255) COLLATE "pg_catalog"."default",
  "relevance2" varchar(255) COLLATE "pg_catalog"."default",
  "new_field" varchar(255) COLLATE "pg_catalog"."default",
  CONSTRAINT "newdb_pkey" PRIMARY KEY ("id")
)
;
ALTER TABLE "public"."newdb" 
  OWNER TO "postgres";
COMMENT ON COLUMN "public"."newdb"."id" IS '主键';
COMMENT ON COLUMN "public"."newdb"."relevance1" IS '关联字段1';
COMMENT ON COLUMN "public"."newdb"."relevance2" IS '关联字段2';
COMMENT ON COLUMN "public"."newdb"."new_field" IS '新字段,需要同步到旧表';
复制代码


提醒:注意数据库是postgresql,其他数据库可能存在字段等差别而无法成功

表成功创建之后,在内部加入一些简单的数据:


网络异常,图片无法展示
|


实现方式汇总



join


第一种的连接方式使用的是连接表的join方法,我们通过关联字段查出对应的关联记录,同时在关联之后将关联新字段的数据更新到旧表,这样就实现了每关联一条记录就更新一条记录数据:


实现方式也比较简单,只需要使用


UPDATE olddb aa
SET new_field = bb.new_field
FROM
   newdb bb where aa.relevance1 = bb.relevance1 
  AND aa.relevance2 = bb.relevance2
复制代码


他的执行结果如下:


网络异常,图片无法展示
|


下面的下方是错的,这时候sql会抛出一个错误。


UPDATE olddb ALIAS 
SET ( new_field ) = (
  SELECT
    ( bb.new_field ) 
  FROM
    olddb aa
    JOIN newdb bb ON aa.relevance2 = bb.relevance2 
    AND aa.relevance1 = bb.relevance1 
  )
复制代码


Merge(未验证)


第二种方式可能比较陌生,因为merge算是对于insert以及update的一个统合,粗略了解了一下发现能干不少事情,下面说下。


注意下面的方法在postgresql 报错,原因是是我的postgresql版本太低,但是个人在升级过后还不能支持使用merge方法 ,所以这里保存了sql,可以改动后尝试到其它的数据库语言进行使用。


ERROR:  syntax error at or near "MERGE"

很头疼,在stackflow也没用找到答案。


merge into olddb as olds
using newdb news on olds.new_field = news.new_field
when matched
update set 
olds.new_field = news.new_field
复制代码


需要注意的是不同的数据库对于merge的特性是不一致的,建议查看当前安装数据库的版本以及文档进行确认比较稳妥。


下面是 postgresqlmerge使用案例,注意一般建议版本为11以上再使用merge


MERGE INTO wines 
USING (VALUES('Chateau Lafite 2003', '24')) v
ON v.column1 = w.winename
WHEN NOT MATCHED 
  INSERT VALUES(v.column1, v.column2)
WHEN MATCHED
  UPDATE SET stock = stock + v.column2;
复制代码


子查询


子查询是最简单也是最容易想到的一种方式,不过子查询有一个明显的缺点就是数据量较大的情况下通常性能都比较差, 这种操作通常适合数据量比较小的情况,下面是对应的案例语法:


UPDATE olddb 
SET new_field = ( SELECT newdb.new_field FROM newdb WHERE olddb.relevance1 = newdb.relevance1 AND olddb.relevance2 = newdb.relevance2 )
复制代码


下面是子查询需要注意的点:


  • 如果子查询无法找到任何匹配的行,则更新后的值将被更改为NULL
  • 如果子查询找到多个匹配的行,update查询将返回一个错误。

错误的信息如下:

> ERROR:  more than one row returned by a subquery used as an expression

(>错误:作为表达式使用的子查询返回多行)

  • 多数情况下子查询的性能较差,尽量避免使用


总结:



由于merge个人使用经验不足,花了较多时间依然没有解决,所以文章标题进行了标记,后续使用了其他的方式避开问题。

update select的实现实际情况复杂多变,这里只列举了最简单的使用情况。

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
缓存 Linux
kswapd0内存过高排查经历
kswapd0内存过高排查经历
677 1
|
JavaScript 前端开发
Element-ui 中表单(Form)验证数字值范围(大小)
Element-ui 中表单(Form)验证数字值范围(大小)
2596 0
Element-ui 中表单(Form)验证数字值范围(大小)
|
SQL 关系型数据库 MySQL
|
Java Maven
intellij idea如何查看项目maven依赖关系图
这篇文章介绍了如何在IntelliJ IDEA中查看项目的Maven依赖关系图,包括使用Maven工具栏和相关操作来展示和查看依赖细节。
|
XML JSON 前端开发
Bpmn.js 进阶指南之原理分析与模块改造(下)
Bpmn.js 进阶指南之原理分析与模块改造
2243 2
poi在指定位置插入图片并浮动
在使用poi操作docx模板文件时,poi直接插入图片是插入内嵌图片 这个图片是占位置的。
1164 0
|
移动开发 安全 网络协议
https(ssl)安全证书配置【H5系统】
https(ssl)安全证书配置【H5系统】
|
前端开发 JavaScript API
React/Vue 实现路由鉴权、导航守卫和路由拦截的优化建议
本文介绍了在 React 和 Vue 中如何实现路由鉴权、导航守卫和路由拦截的方法。路由鉴权是指根据用户权限验证用户是否有权限访问特定的路由页面。导航守卫是在路由切换之前执行的钩子函数,用于控制路由的跳转。路由拦截是在路由处理过程中拦截某些特定路由的行为。本文将介绍 React 和 Vue 中的相关概念和实现方式,并通过示例代码展示如何应用这些概念来实现路由鉴权、导航守卫和路由拦截。
937 2
|
消息中间件 安全 关系型数据库
kswapd0进程对于CPU占有率高的情况下排查到黑客植入脚本,与黑客斗智斗勇的三个回合(一)
kswapd0进程对于CPU占有率高的情况下排查到黑客植入脚本,与黑客斗智斗勇的三个回合
1027 1