将 SQL 服务器合并语句迁移到 Babelfish for Aurora PostgreSQL 的最佳实践

要将 SQL Server 数据库迁移到 适用于 Aurora PostgreSQL 的 Babelfish ,你通常需要执行自动和手动任务。自动任务包括使用带有 -rewrit e 标志的 Babelfish Compass 工具 进行自动代码转换,以及使用 亚马逊云科技 数据库迁移服务 (亚马逊云科技 DMS) 进行数据迁移 。手动任务包括使用 Babelfish Compass 工具检查数据库兼容性、Babelfish 不支持的某些数据库对象的迁移变通办法以及手动验证结果。

在这篇文章中,我们将重点介绍 Babelfish Compass 工具的 -rewrit e 标志功能,该功能会自动将 SQL Server 的 MERGE 语句转换为兼容 BabelFish 的 T-SQL 代码。MERGE 语句是这篇文章中显示的一个示例,但是 -rewrit e 也可以用于其他功能。我们还将讨论手动验证结果的最佳实践。

使用 Babelfish Compass,你可以检查你的源 SQL Server 数据库是否与你的目标 Babelfish 数据库兼容,以及 Babelfish 目前不支持哪些功能且无法迁移。

PostgreSQL 15 支持合并,但是 Babelfish 尚不支持合并。 此外,PostgreSQL MERGE 并不完全等同于 SQL Server 的 MERGE,例如,不支持 RETURNING 和 NOT MATCHED BY SOUR CE

Babelfish Compass-重写旗帜概述

使用 -rewrit e 标志,您可以转换 Babelfish Compass 评估报告中不支持的部分中包含的 MERGE 语句。

在命令提示符下运行 Babelfish 指南针工具:

在 Mac 和 Linux 上运行指南针的说明。

BabelfishCompass.bat MyFirstReport C:\work\merge_example.sql -rewrite -reportoption xref

事实证明,当 Babelfish Compass 评估报告建议手动重写 SQL 代码以使其与 Babelfish 目标兼容时, - rewrite 标志很有用。

你可以省去将 SQL 转换为兼容 BabelFish 的 T-SQL 代码的一些手动操作。但是,您还必须仔细检查相应的重写的 SQL 代码。

理解 SQL Server 合并语句

SQL Server 的 MERGE 将插入、更新和删除合并为一个语句和事务。MERGE 语句从源表中选择行,并在单个事务中对目标表执行多个 DML 操作。

为了演示 SQL Server MERGE 的场景,我们在 SQL Server 数据库和 Babelfish 中创建了以下测试表。

Person_Target 是目标表, Person_Sourc e 是源表,其行根据合并条件合并到 Person_ Target 表中:

CREATE TABLE dbo.Person_Target(
PersonID int NULL,
PersonName varchar(100) NULL
)

CREATE TABLE dbo.Person_Source(
PersonID int NULL,
PersonName varchar(100) NULL
)

以下 INSERT 语句将示例数据插入到 Person_S ource 和 Person_Targ et 表中:

INSERT INTO Person_Source values 
(1,'Ana Carolina Silva') ,(3,'Carlos Salazar'), (4,'John Doe')
INSERT INTO Person_Target values 
(1,'Ana Carolina '),(2,'Diego Ramirez') ,(3,'Carlos Salazar')

以下代码将 Person_S ource 表中的数据合并到 Person_ Targ et 表中,合并后的分号实际上是强制性的:

MERGE Person_Target T
USING Person_Source S ON T.PersonID=S.PersonID

WHEN MATCHED THEN
UPDATE SET PersonName=S.PersonName


WHEN NOT MATCHED BY TARGET
THEN
INSERT (PersonID,PersonName)
VALUES (S.PersonID,S.PersonName)

WHEN NOT MATCHED BY SOURCE
THEN
DELETE;

对于 Per son_ Target 表中的每一行,SQL Server 都会评估被称为合并条件的 搜索条件。 如果条件匹配,则结果变为真,并且 SQL Server 使用来自 Pers on_Sou rce 表的相应数据更新目标表中的行。如果任何行的条件都不匹配,则结果为 false,SQL Server 会将源表中的相应行插入到目标表中。如果源表中任何行的条件都不匹配,则该行将从目标中删除。下图说明了这个工作流程。

我们可以验证目标表并检查 Pers on_Target 表中的数据是否与前面的图表相匹配。

相当于 Babelfish 中的 SQL 服务器合并

因为 PostgreSQL 没有类似合并的直接结构。但是,指南针工具可以将 Babelfish 的 MERGE 重写为单独的 “插入”、“更新” 或 “删除” 语句

以下语句在 Babelfish 中创建 Person_Sour ce 和 Person_Target 表并插入数据:

CREATE TABLE dbo.Person_Target(
PersonID int NULL,
PersonName varchar(100) NULL
);
CREATE TABLE dbo.Person_Source(
PersonID int NULL,
PersonName varchar(100) NULL
);


INSERT INTO Person_Source values 
(1,'Ana Carolina Silva') ,(3,'Carlos Salazar'), (4,'John Doe');
INSERT INTO Person_Target values 
(1,'Ana Carolina '),(2,'Diego Ramirez') ,(3,'Carlos Salazar');

以下代码是在报告文件夹内名为 rewriten 的 文件夹中自动生成的。

/* original MERGE statement -- MERGE Person_Target T
USING Person_Source S ON T.PersonID=S.PersonID

WHEN MATCHED THEN
UPDATE SET PersonName=S.PersonName


WHEN NOT MATCHED BY TARGET
THEN
INSERT (PersonID,PersonName)
VALUES (S.PersonID,S.PersonName)

WHEN NOT MATCHED BY SOURCE
THEN
DELETE; -- end original MERGE statement */

/*REWRITTEN*/ 
/* --- start rewritten MERGE statement #1 --- */
/* Note: please review/modify the rewritten SQL code below, especially for handling of ROLLBACK */
BEGIN TRANSACTION
SAVE TRANSACTION savept_merge_rewritten_1
DECLARE @MERGE_REWRITTEN_ROWCOUNT_1 INT = 0 /* use instead of original @@ROWCOUNT */
DECLARE @MERGE_REWRITTEN_ERROR_1 INT /* temporary variable */
DECLARE @MERGE_REWRITTEN_RCTMP_1 INT /* temporary variable */

/* WHEN MATCHED THEN UPDATE */
UPDATE T
SET PersonName=S.PersonName
FROM 
Person_Target T, 
Person_Source S
WHERE T.PersonID=S.PersonID
SELECT @MERGE_REWRITTEN_ERROR_1=@@ERROR, @MERGE_REWRITTEN_RCTMP_1=@@ROWCOUNT
IF @MERGE_REWRITTEN_ERROR_1 <> 0 GOTO lbl_rollback_merge_rewritten_1
SET @MERGE_REWRITTEN_ROWCOUNT_1 += @MERGE_REWRITTEN_RCTMP_1

/* WHEN NOT MATCHED BY SOURCE THEN DELETE */
DELETE T
FROM Person_Target T
WHERE NOT EXISTS (
SELECT * FROM Person_Source S
WHERE T.PersonID=S.PersonID
)
SELECT @MERGE_REWRITTEN_ERROR_1=@@ERROR, @MERGE_REWRITTEN_RCTMP_1=@@ROWCOUNT
IF @MERGE_REWRITTEN_ERROR_1 <> 0 GOTO lbl_rollback_merge_rewritten_1
SET @MERGE_REWRITTEN_ROWCOUNT_1 += @MERGE_REWRITTEN_RCTMP_1

/* WHEN NOT MATCHED BY TARGET THEN INSERT */
INSERT INTO Person_Target
(PersonID,PersonName)
SELECT S.PersonID,S.PersonName 
FROM Person_Source S
WHERE NOT EXISTS (
SELECT * FROM Person_Target T
WHERE T.PersonID=S.PersonID
)
SELECT @MERGE_REWRITTEN_ERROR_1=@@ERROR, @MERGE_REWRITTEN_RCTMP_1=@@ROWCOUNT
IF @MERGE_REWRITTEN_ERROR_1 <> 0 GOTO lbl_rollback_merge_rewritten_1
SET @MERGE_REWRITTEN_ROWCOUNT_1 += @MERGE_REWRITTEN_RCTMP_1

GOTO lbl_commit_merge_rewritten_1
/* in case of an error, roll back to savepoint at the start but do no abort the transaction: there may be an outermost transaction active*/
lbl_rollback_merge_rewritten_1: ROLLBACK TRANSACTION savept_merge_rewritten_1
lbl_commit_merge_rewritten_1:   COMMIT
;/* --- end rewritten MERGE statement #1 --- */

END
GO

区别之一是 @ @rowcount 与 SQL Server 相比有所不同。这就是为什么我们在重写的代码 中有 @MERGE_RWRITTEN_ROWCOUNT_n

转换该过程的代码后,你可以验证 SQL Server 和 Babelfish PostgreSQL pers on_target 表中的数据是否匹配。

注意事项

当 MERGE 语句在字符串变量中动态构造时,不会使用 Babelfish Compass 工具对其进行重写。在这种情况下,您必须手动对其进行转换。只要 Babelfish 不支持 MERGE, -rewr ite 标志才会影响 MERGE,一旦支持该功能, -rewrite 就 不会再尝试重写它了。

结论

在这篇文章中,我们介绍了 SQL Server 中使用的 MERGE 语句的一个示例,并解释了如何使用 Babelfish Compass 工具中的 -rewrit e 标志将其转换为等效的 Babelfish T-SQL 代码。


作者简介

Shyam Sunder Rakhecha 是位于印度海得拉巴的 亚马逊云科技 专业服务团队的首席顾问,专门研究数据库迁移和现代化。他正在帮助客户在 亚马逊云科技 云中进行迁移和优化。他很想探索数据库方面的新兴技术。他对 RDBMS 和大数据着迷。他还喜欢组织团队建设活动和团队奖励。