我正在编写一个脚本来将环境从一台服务器移植到另一台服务器。我遇到了一个调用问题,catalog.create_environment_variable
其中出现错误“输入值的数据类型与‘字符串’的数据类型不兼容。” 来自过程“check_data_type_value”。
奇怪的是,如果我让 GUI 脚本输出变量,该查询将起作用
DECLARE @var sql_variant = N'\\myserver\ssisdata'
EXEC [catalog].[create_environment_variable]
@variable_name = N'FolderBase'
, @sensitive = False
, @description = N''
, @environment_name = N'Development'
, @folder_name = N'POC'
, @value = @var
, @data_type = N'String'
GO
但是,采用这种脚本方法是行不通的。我所做的工作表明此错误消息通常通过使用 nvarchar 数据类型而不是 varchar 来解决。但是,我的东西不是这样。
以下脚本的第 108 行。我的假设是sql_variant 有点奇怪,但我不知道那是什么。
USE SSISDB;
GO
DECLARE
@folder_id bigint
, @folder_name nvarchar(128) = N'POC'
, @environment_name nvarchar(128) = N'Development'
, @environment_description nvarchar(1024)
, @reference_id bigint
, @variable_name nvarchar(128)
, @data_type nvarchar(128)
, @sensitive bit
, @value sql_variant
, @description nvarchar(1024);
IF NOT EXISTS
(
SELECT * FROM catalog.folders AS F WHERE F.name = @folder_name
)
BEGIN
EXECUTE catalog.create_folder
@folder_name = @folder_name
, @folder_id = @folder_id OUTPUT;
PRINT CONCAT('Folder "', @folder_name, '" has been created with a folder_id of ', @folder_id)
END
IF NOT EXISTS
(
SELECT * FROM catalog.environments AS E WHERE E.name = @environment_name
AND E.folder_id = (SELECT F.folder_id FROM catalog.folders AS F WHERE F.name = @folder_name)
)
BEGIN
PRINT CONCAT('Creating environment ', @environment_name);
EXECUTE catalog.create_environment
@folder_name = @folder_name
, @environment_name = @environment_name
, @environment_description = @environment_description;
END
DECLARE
@EnvironmentVariables TABLE
(
folder_name nvarchar(128)
, environment_name nvarchar(128)
, variable_name nvarchar(128)
, description nvarchar(1024)
, data_type nvarchar(128)
, sensitive bit
, value sql_variant
);
INSERT INTO
@EnvironmentVariables
SELECT
E.folder_name
, E.environment_name
, S.name
, S.description
, S.type
, S.sensitive
, S.value
FROM
(
SELECT 'FolderBase','Root for ssis processing','String',CAST(0 AS bit),'\\myserver\ssisdata'
UNION ALL SELECT 'AuditConnectionString','Conn to audit db','String',CAST(0 AS bit),'Data Source=SQLETL01;Initial Catalog=Audit;Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;'
) AS S (name, description, type, sensitive, value)
CROSS APPLY
(
SELECT
E.name AS environment_name
, F.name AS folder_name
FROM
catalog.folders AS F
INNER JOIN
catalog.environments AS E
ON E.folder_id = F.folder_id
WHERE
F.name = @folder_name
AND E.name = @environment_name
) E;
DECLARE Csr CURSOR FORWARD_ONLY STATIC FOR
SELECT
EV.variable_name
, EV.description
, EV.data_type
, EV.sensitive
, EV.value
FROM
@Environmentvariables AS EV;
OPEN Csr;
FETCH NEXT FROM Csr INTO
@variable_name
, @description
, @data_type
, @sensitive
, @value;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
-- THERE BE MONSTERS AHEAD
-- The data type of the input value is not compatible with the data type of the 'String'.
EXECUTE catalog.create_environment_variable
@variable_name = @variable_name
, @sensitive = @sensitive
, @description = @description
, @environment_name = @environment_name
, @folder_name = @folder_name
, @value = @value
, @data_type = @data_type
END TRY
BEGIN CATCH
SELECT
@folder_name AS folder_name
, @environment_name AS environment_name
, @variable_name AS variable_name
, @data_type AS data_type
, @sensitive AS sensitive
, @value AS value
, @description AS description
, ERROR_NUMBER()AS error_number --returns the number of the error.
, ERROR_SEVERITY() AS error_severity --returns the severity.
, ERROR_STATE()AS error_state --returns the error state number.
, ERROR_PROCEDURE() AS error_procedure --returns the name of the stored procedure or trigger where the error occurred.
, ERROR_LINE() AS error_line --returns the line number inside the routine that caused the error.
, ERROR_MESSAGE() AS error_message; --returns the complete text of the error message. The text includes the values supplied for any substitutable parameters, such as lengths, object names, or times.
END CATCH
FETCH NEXT FROM Csr INTO
@variable_name
, @description
, @data_type
, @sensitive
, @value;
END
CLOSE Csr;
DEALLOCATE Csr;
“我所做的工作表明此错误消息通常可以通过使用 nvarchar 数据类型而不是 varchar 来解决。但是,我的东西并非如此。” 或者是这样吗?
我对光标进行了两次更改。第一个在我的 CATCH 块中。我重新阅读了有关 sql_variant 数据类型的文章,然后是sql_variant_property。我在我的 catch 块中添加了一个调用,期望看到
nvarchar
但你瞧,它报告varchar
为我的 BaseType。知道这一点并且我的所有源数据都是基于字符的,我作弊并将
@local
具有显式强制转换的变量添加到 nvarchar 并且它神奇地起作用。根本原因分析
当我开始撰写调查结果摘要时,我发现了这种脱节。当我加载我的临时表 @EnvironmentVariables 时,我最初是直接从那里获取的,
catalog.environment_variables.
为了使其更便携,我将这些值复制为 SELECT 语句。这就是我搞砸的地方。当我重构这些值时,我将 Unicode 字符串变成了“mercan 字符串”。它们被作为非 unicode 写入 sql_variant 类型列,然后当它在 proc 中传递以进行验证时爆炸。如果我正确地在我的字符串前面加上N
修饰符(?),它们将存储为 nvarchar。只是为了添加到@billinkc 出色的答案(当然你知道你会是回答这个问题的人!!)并丰富这方面的知识......
这是一些示例代码,从这里自动生成https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/抛出错误:
具体的错误是
我还有其他日期时间和布尔值错误
因此,在没有深入理解问题的情况下,解决方案基本上是使用特定的数据类型,而不是
sql_variant
在将值传递给@value
参数时。对于 Int64 和 Boolean,您可以对值进行硬编码,但
datetime
您必须预先声明一个类型的变量datetime
并使用它 - 您不能只传入字符串日期文字这是我第一次看到存储过程中的参数显然可以接受多种数据类型。