当数据库兼容级别设置为 SQL Server 2008 时,如何在 SSIS OLE DB 源 SQL 命令中使用 STRING_SPLIT?

How to using STRING_SPLIT within an SSIS OLE DB Source SQL Command when the database compatibility level is set to is set to SQL Server 2008?

我在服务器 1 上有一个 SSIS 程序包。它通过 OLEDB 源 sql 命令文本对位于服务器 2 上的 SQL 数据库执行 SQL 查询。查询是:

SELECT * FROM PRODUCTS
WHERE PRODUCT_NAME IN (?)

这失败了,因为?是标量值而不是 table。要解决此问题,有 2 个选项:

  1. 使用STRING_SPLIT
  2. Create string split function

我不能使用选项 1,因为虽然它是 SQL 服务器 2017,但数据库兼容级别设置为 2008(级别 100)。 STRING_SPLIT 仅支持更高的兼容性级别。我不能更改此设置。

我不能使用选项 2,因为不允许我在该数据库上创建任何新的自定义函数。

有解决办法吗?我已阅读有关将自定义函数添加到主数据库中的信息,但不确定未来 SQL 更新是否会重置它,因为用户函数不应该放在主数据库中。

一种方法是将上下文切换到 确实 具有所需兼容性级别(下面的tempdb)的数据库。

DECLARE @ProductNames VARCHAR(MAX) = ? 

CREATE TABLE #ProductNames
(
PRODUCT_NAME VARCHAR(50) PRIMARY KEY
)

EXEC tempdb.sys.sp_executesql N'INSERT INTO #ProductNames SELECT DISTINCT value FROM STRING_SPLIT(@ProductNames, '','')',
                       N'@ProductNames VARCHAR(MAX)',
                       @ProductNames = @ProductNames;

SELECT *
FROM   PRODUCTS
WHERE  PRODUCT_NAME IN (SELECT pn.PRODUCT_NAME
                        FROM   #ProductNames pn)

DROP TABLE #ProductNames 

您可以将字符串加载到参数对象 @ProductNames 中,然后将其用作源,然后在另一个数据流中内部加入产品 table。

第一个 DF: 以@stringToParse 作为变量的脚本组件源。在 ProductName 的 DF 中也有输出字符串。

代码:

string prods = Variables.stringToParse.Value;
string[] productNames = prods.Split(',');
foreach(string p in productNames)
{
    OutputBuffer0.AddRow();
    OutputBuffer0.ProductName = p;
}

然后将结果加载到映射到@ProductNames 的记录集目标中。

第二个测距仪: 2 个来源。

  1. 产品Table
  2. 您的记录集@ProductNames

进行合并联接(内部),您将拥有自己的记录。

STRING_SPLIT备选方案

如以下回答T-SQL split string所述, 以下 SQL 查询可以替换 STRING_SPLIT 函数:

SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
SELECT CAST ('<M>' + REPLACE(/*Comma separated value should be placed here*/, ',', '</M><M>') + '</M>' AS XML) AS Data            
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)

使用 OLE DB 源 SQL 命令

如果您使用的是 OLE DB 源组件,则可以使用以下 SQL 命令:

DECLARE @String varchar(100) = ?;

SELECT * FROM PRODUCTS
WHERE PRODUCT_NAME IN (
SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
SELECT CAST ('<M>' + REPLACE(@String , ',', '</M><M>') + '</M>' AS XML) AS Data            
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)
)

测试

使用 AdventureWorks2017 数据库,我使用以下查询来搜索存储在 [Person].[Person] table 中的人员信息,同时过滤器位于 PersonType 列:

DECLARE @String varchar(100) = ?;

SELECT * FROM [AdventureWorks2017].[Person].[Person]
WHERE PersonType IN (
SELECT LTRIM(RTRIM(Split.a.value('.', 'VARCHAR(100)'))) 'Value' 
FROM  
(     
SELECT CAST ('<M>' + REPLACE(@String , ',', '</M><M>') + '</M>' AS XML) AS Data            
) AS A 
CROSS APPLY Data.nodes ('/M') AS Split(a)
)

在 OLE DB 源代码编辑器中,如果我们单击 Parameters 按钮,将识别一个参数。我将创建一个新变量并将其用作参数,如下图所示:

变量数据类型应设置为String,值设置为EM,SC,这两个符号均在PersonType列中使用。

现在,如果我们在 OLE DB 源代码编辑器中单击 预览 按钮,就会显示准确的数据。