首页 > 解决方案 > 查询中的对象变量

问题描述

我正在使用 SSDT 2017 并且我正在研究一种解决方案,该解决方案基本上从​​查询中获取完整的结果集到变量中(仅 1 列:AccountID),并且我需要在查询中包含该对象变量中的值,例如这:

"SELECT * FROM dbo.account WHERE AccountID IN (" + @AccountIDObjectVariable + ")"

我尝试使用表达式,但出现错误,所以我不确定是否有更好的方法,我也尝试了 for each 循环容器逻辑,但由于我在对象变量中有数百万条记录,我认为这不是最好的方法。

任何的想法?

标签: sqlssis

解决方案


它不是那样工作的。“它”将成为很多东西。

SSIS 数据类型是原始类型(布尔、日期、数字)或对象。Object 唯一支持的操作是空检查和枚举。

SSIS 参数化仅用于基于相等的替换。SQL 中没有列表数据类型的概念,因此 SSIS 中没有类似的数据类型。

我在对象变量中有数百万条记录

即使您将列表转换为字符串并使用字符串连接,您将遇到的下一个问题是字符串长度限制为 4000 个字符。

方法是什么?

让我们重新解决问题:您有一组来自源系统的重要身份。这组 id 需要用作后续提取的基础。

是身份来源和实际数据在同一台服务器上

虽然您可以用茶匙清空海洋,但这不是正确的工具。这里也一样。将标识要提取的记录集的查询移动到源的筛选条件中。

即加载数据集到@AccountIDObjectVariable

SELECT
    OA.AccountId
FROM
    dbo.OutstandingAccount AS OA;

提取不工作

"SELECT * FROM dbo.account WHERE AccountID IN (" + @AccountIDObjectVariable + ")"

被改写为

SELECT * FROM dbo.account AS A WHERE EXISTS (SELECT * FROM dbo.OutstandingAccount AS OA WHERE OA.AccountID = A.AccountID);

有两种合理的方法可以解决这个问题

全部拉

如果源 ID 列表和源表具有相似的数量级,则将其全部关闭并在查找任务中使用帐户 ID 生成查询可能更容易。如果 AccountID 存在,那么它就是您想要的数据。是的,你拉的比你想要的要多,但你可能会花费更多的周期和复杂性来尝试有选择地拉你想要的东西。

推和拉

这种方法适用于 SQL Server,我不知道任何其他数据库。好吧,我想 Sybase 将是相同的给定数据库亲子关系。

打开 SSMS 并在 dbo.account 所在的数据库上创建一个全局临时表。不要断开与 SSMS 的连接。

IF OBJECT_ID('tempdb..##SO_66961235') IS NOT NULL
BEGIN
    DROP TABLE ##SO_66961235;
END
GO
CREATE TABLE ##SO_66961235
(
    AccountID int NOT NULL
);

修改连接管理器以将 RetainSameConnection 属性设置为 true,以便数据库连接到 dbo.account

执行 SQL 任务 - 制作临时表 使用与帐户数据库的连接和上述查询。这将确保该表存在,以便 SSIS 的未来会话正常工作。

数据流负载 ID 在数据流属性中,将 DelayValidation 设置为True

使用您的源查询生成 ID 列表并选择临时表作为目标。您可能需要让该系统运行第二个连接管理器并指向 tempdb,我已经很久没有这样做了。不过,关于 RetainSameConnection 的相同规则将适用。

当此数据流完成时,我们将在数据源服务器上拥有一个可以引用的临时表。

数据流 2 再次获取数据 ,DelayValidation 为 true。

源将是一个查询

SELECT * FROM dbo.account AS A WHERE EXISTS (SELECT * FROM ##SO_66961235 AS OA WHERE OA.AccountID = A.AccountID);

所有延迟验证是怎么回事?

当 SSIS 包启动时,它要做的第一件事是确保所有部分都已就位以使其成功运行,不仅各部分都已就位,数据的形状是否仍然相同?包启动时临时表将不存在,并且包将失败并出现 VS_NEEDSNEWMETADATA 错误。设置 DelayValidation 告诉 SSIS 在组件检查元数据之前,它不应该担心检查,直到组件真正获得启动信号。由于我们定义了前驱执行 SQL 任务来创建表,因此验证应该会成功。

我在这里使用了全局临时表。您可以使用本地范围的临时表,但它使已经很繁琐的设计过程更加如此。如果是我,我会有一个包参数控制一个布尔值,它使用全局临时表进行开发会话,使用本地临时表进行实际运行时操作,但这超出了这个问题的范围。


推荐阅读