SSIS - 如果源数据集中的任何行有缺失值,则失败?
SSIS - Fail if any row in the source dataset has missing values?
假设我有以下数据:
FirstName | LastName | Age | Date Added to Database (derived column)
John | Doe | 23 | dd/mm/yyyy
Jane | Doe | 31 | dd/mm/yyyy
Bob | | 40 | dd/mm/yyyy
Janet | Smith | | dd/mm/yyyy
我想将它从 Excel/Flat 文件源导入到 Sql 服务器。但是,如果源数据集中的 any 行缺少值,我希望任务完全失败。到目前为止,我已经看到了我们可以做这样的事情的教程:
如果具有空值的记录包含空值,则它们将被拆分。但是,如果任何值为空,我根本不想插入任何值,而是我想做一些事情,比如在失败时发送一封电子邮件,通知缺少值。
这在 SSIS 中可行吗?可以通过分段 table 等来完成吗?
这可以通过分期完成 table。对于您的示例数据,您将使用下面的 DDL。
诀窍是在每一列上都有一个 NOT NULL 约束。有关约束的更多信息,请参阅 SQLShack 上的博客 post。
当 SSIS 尝试插入 NULL 值时,它将失败。不是最优雅的解决方案,但可以在没有太多开销的情况下完成您的要求。
CREATE TABLE Staging
(
FirstName VARCHAR(50) NOT NULL
, LastName VARCHAR(50) NOT NULL
, Age INT NOT NULL
, DateAdded DATETIME NOT NULL
)
开箱即用的东西都不能直接支持这种情况,但我可以想到一些您可以拼凑起来的方法来实现您的要求。
要实现的 cleanest/easiest 只是将所有数据填充到暂存 table 中,由于我很懒,我会在 table 定义中添加一个计算列将一行标记为某处有空值。
ALTER TABLE dbo.stageData
ADD HasNull AS (CASE WHEN Col1 IS NULL OR Col2 IS NULL THEN 'Y' ELSE 'N');
然后您将在数据流之后添加两个执行 SQL 任务。第一个发送电子邮件(假设您已 msdb.dbo.sp_send_dbmail 设置)我会做一些事情
IF EXISTS (SELECT * FROM dbo.StageData AS SD WHERE SD.HasNull = 'Y')
BEGIN
EXECUTE msdb.dbo.sp_send_db_mail @recipient = 'ocean800', @subject = 'Null detected';
END
然后我会有一个执行 SQL 任务,将数据从阶段捕捉到最终 table。在这里仔细检查我的逻辑,因为我没有对此进行编码。它可能需要是 ANY 或只是重复发送邮件逻辑并将插入作为 ELSE 子句。见鬼,这可能更简单...
INSERT INTO dbo.Final SELECT * FROM dbo.StageData AS SD WHERE NOT EXISTS (SELECT * FROM dbo.StageData AS SDI SDI.HasNull ='Y');
没有阶段的方法 table 将对您的文件进行双重处理。第一个数据流将是平面文件源到条件拆分,然后……不管是什么。我会轻松使用行计数转换,该转换将填充您创建的名为 RowsNull 的 SSIS 变量。数据流运行后,您的值为零(适合加载)或大于零 - 发送电子邮件。
将数据流任务分叉为数据流任务,后者实际存储到我们的 table 和通知(发送电子邮件任务、执行 SQL 发送电子邮件的任务,等等)。
这里的技巧是修改父任务(数据流)和子路径之间的 Precedent Constraint。您将把它设置为 Expression and Constraint。约束仍然成功并且约束是@[User::RowsNull] == 0 和@[User::RowsNull] > 0
其他不太好的方法可能是指定 OLE DB 目标保留默认设置(每批行数为空,最大插入提交大小为最大 int)该设置是全有或全无提交 - 您只需要一些东西要在 HasNull 路径的条件拆分上炸毁隐式事务,请将行路由到引发错误事件的脚本任务。那会杀死负载。或者在这些列上使用 NOT NULL 说明符定义您的目标 table,然后数据将加载或不加载,您只需将您偏好的电子邮件任务添加到数据流的失败先例约束中,以便在加载失败时通知.
您绝对可以利用暂存 table 作为数据流的中间点,然后在进一步移动之前验证 SQL 中所需的任何逻辑。这种方法非常简单,而且有一个额外的好处,即每当您的流程失败时,您的暂存 table 将包含最新文件中的所有数据,因此调查起来更容易。
我能想到的所有替代方案在性能和/或所需资源方面都要差得多,而且通常不会使用。例如,理论上可以通过 Script Task source into an in-memory ADO recordset 加载文件数据,在将它们发送到输出缓冲区时检查脚本中的值,如果数据有任何错误则抛出异常。如果此数据流没有失败,那么下一步可能会将数据从该记录集中加载到实际的 table.
(免责声明:上述替代方案非常笨拙且效率低下,永远不应被视为可行的方法。我不知道从哪里开始描述它的缺点。就个人而言,只有在我的实际情况下,我才会考虑类似的方法目标是 "screw things up as much as I can without giving my employer a formal casus belli",我从来没有这样做过。)
假设我有以下数据:
FirstName | LastName | Age | Date Added to Database (derived column)
John | Doe | 23 | dd/mm/yyyy
Jane | Doe | 31 | dd/mm/yyyy
Bob | | 40 | dd/mm/yyyy
Janet | Smith | | dd/mm/yyyy
我想将它从 Excel/Flat 文件源导入到 Sql 服务器。但是,如果源数据集中的 any 行缺少值,我希望任务完全失败。到目前为止,我已经看到了我们可以做这样的事情的教程:
如果具有空值的记录包含空值,则它们将被拆分。但是,如果任何值为空,我根本不想插入任何值,而是我想做一些事情,比如在失败时发送一封电子邮件,通知缺少值。
这在 SSIS 中可行吗?可以通过分段 table 等来完成吗?
这可以通过分期完成 table。对于您的示例数据,您将使用下面的 DDL。
诀窍是在每一列上都有一个 NOT NULL 约束。有关约束的更多信息,请参阅 SQLShack 上的博客 post。
当 SSIS 尝试插入 NULL 值时,它将失败。不是最优雅的解决方案,但可以在没有太多开销的情况下完成您的要求。
CREATE TABLE Staging
(
FirstName VARCHAR(50) NOT NULL
, LastName VARCHAR(50) NOT NULL
, Age INT NOT NULL
, DateAdded DATETIME NOT NULL
)
开箱即用的东西都不能直接支持这种情况,但我可以想到一些您可以拼凑起来的方法来实现您的要求。
要实现的 cleanest/easiest 只是将所有数据填充到暂存 table 中,由于我很懒,我会在 table 定义中添加一个计算列将一行标记为某处有空值。
ALTER TABLE dbo.stageData
ADD HasNull AS (CASE WHEN Col1 IS NULL OR Col2 IS NULL THEN 'Y' ELSE 'N');
然后您将在数据流之后添加两个执行 SQL 任务。第一个发送电子邮件(假设您已 msdb.dbo.sp_send_dbmail 设置)我会做一些事情
IF EXISTS (SELECT * FROM dbo.StageData AS SD WHERE SD.HasNull = 'Y')
BEGIN
EXECUTE msdb.dbo.sp_send_db_mail @recipient = 'ocean800', @subject = 'Null detected';
END
然后我会有一个执行 SQL 任务,将数据从阶段捕捉到最终 table。在这里仔细检查我的逻辑,因为我没有对此进行编码。它可能需要是 ANY 或只是重复发送邮件逻辑并将插入作为 ELSE 子句。见鬼,这可能更简单...
INSERT INTO dbo.Final SELECT * FROM dbo.StageData AS SD WHERE NOT EXISTS (SELECT * FROM dbo.StageData AS SDI SDI.HasNull ='Y');
没有阶段的方法 table 将对您的文件进行双重处理。第一个数据流将是平面文件源到条件拆分,然后……不管是什么。我会轻松使用行计数转换,该转换将填充您创建的名为 RowsNull 的 SSIS 变量。数据流运行后,您的值为零(适合加载)或大于零 - 发送电子邮件。
将数据流任务分叉为数据流任务,后者实际存储到我们的 table 和通知(发送电子邮件任务、执行 SQL 发送电子邮件的任务,等等)。 这里的技巧是修改父任务(数据流)和子路径之间的 Precedent Constraint。您将把它设置为 Expression and Constraint。约束仍然成功并且约束是@[User::RowsNull] == 0 和@[User::RowsNull] > 0
其他不太好的方法可能是指定 OLE DB 目标保留默认设置(每批行数为空,最大插入提交大小为最大 int)该设置是全有或全无提交 - 您只需要一些东西要在 HasNull 路径的条件拆分上炸毁隐式事务,请将行路由到引发错误事件的脚本任务。那会杀死负载。或者在这些列上使用 NOT NULL 说明符定义您的目标 table,然后数据将加载或不加载,您只需将您偏好的电子邮件任务添加到数据流的失败先例约束中,以便在加载失败时通知.
您绝对可以利用暂存 table 作为数据流的中间点,然后在进一步移动之前验证 SQL 中所需的任何逻辑。这种方法非常简单,而且有一个额外的好处,即每当您的流程失败时,您的暂存 table 将包含最新文件中的所有数据,因此调查起来更容易。
我能想到的所有替代方案在性能和/或所需资源方面都要差得多,而且通常不会使用。例如,理论上可以通过 Script Task source into an in-memory ADO recordset 加载文件数据,在将它们发送到输出缓冲区时检查脚本中的值,如果数据有任何错误则抛出异常。如果此数据流没有失败,那么下一步可能会将数据从该记录集中加载到实际的 table.
(免责声明:上述替代方案非常笨拙且效率低下,永远不应被视为可行的方法。我不知道从哪里开始描述它的缺点。就个人而言,只有在我的实际情况下,我才会考虑类似的方法目标是 "screw things up as much as I can without giving my employer a formal casus belli",我从来没有这样做过。)