在部署数据库项目期间,我们遇到了需要将数据从一个表转换到另一个表的情况。当然,使用数据库项目是一个问题,因为在部署前目标表(列)仍然不存在,但在部署后脚本中源表(列)已经不存在。
为了将数据从 TableA 转换到 TableB,我们使用了以下想法(这种方法可以用于任何数据修改):
- 开发人员将目标表 (dbo.TableB) 添加到 DB 项目中并将其部署到本地 DB(无需提交到 SVN)
- 他或她创建了一个预部署转换脚本。诀窍是脚本将结果数据放入临时表中:#TableB
- 开发人员删除了 DB 项目中的 dbo.TableA。假设在生成的主脚本执行期间该表将被删除。
- 开发人员编写了一个部署后脚本,将数据从#TableB 复制到主脚本刚刚创建的 dbo.TableB。
- 所有更改都提交到 SVN。
这样我们不需要预部署脚本,因为我们将中间数据存储在临时表中。
我想说的是,使用预部署脚本的方法具有相同的中间(临时)数据,但是它不是存储在临时表中,而是存储在真实表中。它发生在预部署和预部署之间。执行预部署脚本后,此中间数据消失。
更重要的是,使用临时表的方法让我们面临以下复杂但真实的情况:假设我们的数据库项目中有两个转换:
- 表A -> 表B
- 表B->表C
除此之外,我们还有两个数据库:
- 具有 TableA 的DatabaeA
- DatabaeB,其中 TableA 已转换为 TableB。数据库 B 中没有表 A。
尽管如此,我们可以处理这种情况。我们只需要在部署前执行一项新操作。在转换之前,我们尝试将数据从 dbo.TableA 复制到 #TableA。并且转换脚本仅适用于临时表。
让我向您展示这个想法如何在 DatabaseA 和 DatabaseB 中发挥作用。
假设 DB 项目有两对部署前和部署后脚本:“TableA -> TableB”和“TableB -> TableC”。
以下是“TableB -> TableC”转换的脚本示例。
预部署脚本
----[The data preparation block]---
--We must prepare to possible transformation
--The condition should verufy the existance of necessary columns
IF OBJECT_ID('dbo.TableB') IS NOT NULL AND
OBJECT_ID('tempdb..#TableB') IS NULL
BEGIN
CREATE TABLE #TableB
(
[Id] INT NOT NULL PRIMARY KEY,
[Value1] VARCHAR(50) NULL,
[Value2] VARCHAR(50) NULL
)
INSERT INTO [#TableB]
SELECT [Id], [Value1], [Value2]
FROM dbo.TableB
END
----[The data transformation block]---
--The condition of the transformation start
--It is very important. It must be as strict as posible to ward off wrong executions.
--The condition should verufy the existance of necessary columns
--Note that the condition and the transformation must use the #TableA instead of dbo.TableA
IF OBJECT_ID('tempdb..#TableB') IS NOT NULL
BEGIN
CREATE TABLE [#TableC]
(
[Id] INT NOT NULL PRIMARY KEY,
[Value] VARCHAR(50) NULL
)
--Data transformation. The source and destimation tables must be temporary tables.
INSERT INTO [#TableC]
SELECT [Id], Value1 + ' '+ Value2 as Value
FROM [#TableB]
END
部署后脚本
--Here must be a strict condition to ward of a failure
--Checking of the existance of fields is a good idea
IF OBJECT_ID('dbo.TableC') IS NOT NULL AND
OBJECT_ID('tempdb..#TableC') IS NOT NULL
BEGIN
INSERT INTO [TableC]
SELECT [Id], [Value]
FROM [#TableC]
END
在 DatabaseA 中,预部署脚本已经创建了#TableA。因此,由于数据库中没有 dbo.TableB,因此不会执行数据准备块。
但是数据转换将被执行,因为数据库中有由“TableA -> TableB”的转换块创建的#TableA。
在 DatabaseB 中,“TableA -> TableB”脚本的数据准备和转换块不会被执行。但是,我们已经在 dbo.TableB 中获得了转换后的数据。因此,“TableB -> TableC”的数据准备和转换块将毫无问题地执行。