PostgreSQL類似OracleMERGE功能的實現
概述
MERGE語句是Oracle9i新增的語法,用來合併UPDATE和INSERT語句。通過MERGE語句,根據一張表或子查詢的連線條件對另外一張表進行查詢,連線條件匹配上的進行UPDATE,無法匹配的執行INSERT。這個語法僅需要一次全表掃描就完成了全部工作,執行效率要高於INSERT+UPDATE
而PostgreSQL中不直接支援這個語法,但PostgreSQL可以使用WITH Queries (Common Table Expressions)的方法實現相同的功能。
下面我們就來一起看一下
語句詳解
下面這條SQL是把test2表中的資料merge到test1表中,其中主鍵欄位為id
WITH upsert AS (
UPDATE test1
SET col1 = test2.col1
FROM test2
WHERE test1.id = test2.id
RETURNING test1.*
)
INSERT INTO test01
SELECT *
FROM test2
WHERE NOT EXISTS (
SELECT 1
FROM upsert b
WHERE test2.id = b.id
);
其實這段SQL的的重點就是利用了postgresql的一個update特性————RETURNING,返回一個update的結果集,因為查詢條件的存在(也因為它是主鍵,是唯一),就會將兩張表重疊的部分給過濾出來,再用where not exists將這些重疊的部分給忽略掉。這樣就將資料merge進去了
小測試
建兩張表
postgres=# create table test1(id int primary key,name text);
CREATE TABLE
postgres=#
postgres=# create table test2(id int primary key,name text);
CREATE TABLE
資料部分重疊
postgres=# select * from test1;
id | name
----+-------
1 | aaaaa
2 | aaaaa
3 | aaaaa
4 | aaaaa
5 | aaaaa
(5 rows)
postgres=# select * from test2;
id | name
----+-------
4 | aaaaa
5 | aaaaa
6 | bbbbb
7 | bbbbb
8 | bbbbb
9 | bbbbb
(6 rows)
執行merge語句
用test2 這張表去更新test1 ,會將test1 中沒有的資料插入,有的則不會改變
postgres=# WITH upsert AS (
UPDATE test1
SET name = test2.name
FROM test2
WHERE test1.id = test2.id
RETURNING test1.*
)
INSERT INTO test1
SELECT *
FROM test2
WHERE NOT EXISTS (
SELECT 1
FROM upsert b
WHERE test2.id = b.id
);
INSERT 0 4
postgres=# select * from test1;
id | name
----+-------
1 | aaaaa
2 | aaaaa
3 | aaaaa
4 | aaaaa
5 | aaaaa
6 | bbbbb
7 | bbbbb
8 | bbbbb
9 | bbbbb
(9 rows)
可以看到,資料已經更新進來了
一個注意點
在我實際的業務場景更新中,我發現一個需要注意的地方,那就是客戶的test2表,ID列不是主鍵,且有許多重複
檢視ID列有多少重複的SQL如下,如果為0,則說明沒有重複值
select count(*) from users_purse where id in (select id from users_purse group by id having COUNT(*)>1)
如果遇到這種情況,有可能就會出錯,因為test1.ID是不可重複的,所以就可能需要先對其做去重處理distinct。
相關文章
- 教你如何用SQLite 實現if not exist 類似功能的操作SQLite
- 用 hyperf websocket 實現,類似 qq 單機登入功能Web
- lakeFS:實現類似於Git或事件溯源ES的物件儲存功能Git事件物件
- MySQL 06 mysql 如何實現類似 oracle 的 merge intoMySqlOracle
- 用 golang 去實現類似 swoole 的 websocket 服務 ?GolangWeb
- 如何實現類似 lodash 的 get 與 merge 函式函式
- flutter實現類似優惠券樣式Flutter
- Flutter 實現類似TabPicker省市區選擇Flutter
- 用RecyclerView實現類似支付寶應用圖示拖拽排序以及增刪管理的功能View排序
- 100多行程式碼實現js或者jquery版的類似juejin的預覽圖片功能行程JSjQuery
- postgresql使用pgagent來實現job功能SQL
- 採用 SwiftNIO 實現一個類似 Express 的 Web 框架SwiftExpressWeb框架
- 在dotnet core實現類似crontab的定時任務
- Laravel 小技巧 - 讓路由實現類似 Model::query 的效果Laravel路由
- 深度解析:在 React 中實現類似 Vue 的 KeepAlive 元件ReactVue元件
- Blazor如何實現類似於微信的Tab切換?Blazor
- 使用PasteSpider實現類似Jenkins的功能,讓你的2G伺服器也可以飛起ASTIDEJenkins伺服器
- 開源一個自用的Android事件分發中心庫,實現類似系統廣播功能。Android事件
- 類似淘票票 選座功能(svg)SVG
- 使用KubernetesIngress來實現類似Istio條件路由路由
- H5開發類似rpx實現方法H5
- 用Java 19實現類似Go併發 - mccueJavaGo
- 在鴻蒙中實現類似瀑布流效果鴻蒙
- WinForm使用DataGridView實現類似Excel表格的查詢替換ORMViewExcel
- 01 . Go之從零實現Web框架(類似Gin)GoWeb框架
- 原生JS實現類似《掘金》網站的圖片檢視器JS網站
- 使用.net standard實現不同內網埠的互通(類似花生殼)內網
- [Swift]SpriteKit實現類似畫素鳥的小遊戲 - Crashy PlaneSwift遊戲
- mysql中substring_index類似split分組功能MySqlIndex
- iOS動畫系列之七:實現類似Twitter的啟動動畫iOS動畫
- 不到200行用Vue實現類似Swiper.js的輪播元件VueJS元件
- go實現類似與spring的全域性上下文獲取getPrincipal()GoSpring
- 【搜尋引擎】 PostgreSQL 10 實時全文檢索和分詞、相似搜尋、模糊匹配實現類似Google搜尋自動提示SQL分詞Go
- LiveKit:使用Go與WebRTC實現類似Zoom高影片質量GoWebOOM
- GetX 實現類似微信轉發搜尋多選好友
- DeepMind認為他們的神經網路可以實現類似人類的想象力 - kdnuggets神經網路
- SpringBoot+WebFlux透過流式響應實現類似ChatGPT的打字機效果Spring BootWebUXChatGPT
- 類似dreamweaver在VSCode實現網頁製作的靜態CMS:Front MatterVSCode網頁