当数据库兼容级别设置为 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 个选项:
- 使用STRING_SPLIT
- 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 个来源。
- 产品Table
- 您的记录集@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 源代码编辑器中单击 预览 按钮,就会显示准确的数据。
我在服务器 1 上有一个 SSIS 程序包。它通过 OLEDB 源 sql 命令文本对位于服务器 2 上的 SQL 数据库执行 SQL 查询。查询是:
SELECT * FROM PRODUCTS
WHERE PRODUCT_NAME IN (?)
这失败了,因为?是标量值而不是 table。要解决此问题,有 2 个选项:
- 使用STRING_SPLIT
- 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 个来源。
- 产品Table
- 您的记录集@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 源代码编辑器中单击 预览 按钮,就会显示准确的数据。