Falha na variável de ambiente Criar SSIS 2012

12

Estou trabalhando em um script para portar um ambiente de um servidor para outro. Estou enfrentando um problema ao chamar catalog.create_environment_variableo erro "O tipo de dados do valor de entrada não é compatível com o tipo de dados da 'String'". saindo do processo "check_data_type_value".

O que é estranho é que, se eu deixar o script da GUI exibir as variáveis, essa consulta funcionará

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

No entanto, adotar essa abordagem de script não está funcionando. O trabalho que fiz indica que essa mensagem de erro geralmente é resolvida usando o tipo de dados nvarchar em vez de varchar. No entanto, esse não é o caso das minhas coisas.

Linha 108 para o seguinte script. Minha suposição é que é instável algo com o sql_variant , mas eu não tenho idéia o que essa coisa é.

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;
billinkc
fonte
7
Filho. Estou desapontado
swasheck 17/07
5
@swasheck Você sabe quanto orgulho foi engolido antes que eu pudesse clicar no botão Enviar?
billinkc
Não estou desapontado, você acabou de salvar minha noite. Freaking nVarChar
RThomas

Respostas:

10

"O trabalho que fiz indica que essa mensagem de erro geralmente é resolvida usando o tipo de dados nvarchar em vez de varchar. No entanto, esse não é o caso das minhas coisas." Ou é o caso?

Eu fiz duas alterações no meu cursor. O primeiro está no meu bloco CATCH. Reli o artigo sobre o tipo de dados sql_variant e segui com a sql_variant_property . Adicionei uma chamada a isso no meu bloco de captura, esperando ver nvarcharapenas eis que ele é reportado varcharcomo meu BaseType.

Sabendo que e que todos os meus dados de origem são baseados em caracteres, trapacei e adicionei a @localvariável com uma conversão explícita ao nvarchar e funciona magicamente.

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'. 
        DECLARE
            @local nvarchar(4000) = CONVERT(nvarchar(4000), @value);
        EXECUTE catalog.create_environment_variable
            @variable_name = @variable_name
        ,   @sensitive = @sensitive
        ,   @description = @description
        ,   @environment_name = @environment_name
        ,   @folder_name = @folder_name
        ,   @value = @local
        ,   @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
        ,   SQL_VARIANT_PROPERTY(@value, 'BaseType') As BaseType
        ,   @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;

Análise de causa raiz

Quando comecei a escrever um resumo das descobertas, descobri a desconexão. Enquanto carregava minha tabela temporária, @EnvironmentVariables, originalmente a originara diretamente de catalog.environment_variables.Para torná-la mais portátil, copiei os valores como instruções SELECT. Aqui é onde eu estraguei tudo. Quando reconstituí esses valores, transformei as strings Unicode em 'strings mercan. Eles foram gravados na coluna do tipo sql_variant como não unicode, que explodiu quando foi passada no proc para validação. Se eu prefácio corretamente minhas strings com o Nmodificador (?), Elas são armazenadas como nvarchar.

FROM
(
    SELECT 'FolderBase','Root for ssis processing','String',CAST(0 AS bit),N'\\myserver\ssisdata'
    UNION ALL SELECT 'AuditConnectionString','Conn to audit db','String',CAST(0 AS bit),N'Data Source=SQLETL01;Initial Catalog=Audit;Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;'
) AS S (name, description, type, sensitive, value)
billinkc
fonte
Eu usei uma variante deste thefirstsql.com/2013/05/28/… para gerar meu script /. Se entendi corretamente, preciso garantir que todos os meus literais de sequência comecem, Nmas ainda tenho esse problema. Na verdade, recebo reclamações sobre booleano e datetime, mas nenhum dos meus parâmetros usa tipos de dados htese. Você tem alguma ideia?
Nick.McDermaid
1

Só para adicionar uma excelente resposta à @billinkc (certamente você sabia que seria o único a responder a essa pergunta !!) e enriquecer o conhecimento sobre isso ....

Aqui está um exemplo de código, gerado automaticamente aqui https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/ que gera o erro :

DECLARE @var sql_variant

SET @var = '2'
IF NOT EXISTS (
    SELECT 1 FROM [catalog].[environment_variables] 
    WHERE environment_id = @environment_id 
    AND name = N'MyVariable')
EXEC [catalog].[create_environment_variable] 
    @variable_name=N'SystemCd', 
    @sensitive=0, @description=N'', 
    @environment_name=@env_name, 
    @folder_name=@folder, 
    @value=@var, 
    @data_type=N'Int64'

Especificamente, o erro é

Msg 27147, Nível 16, Estado 1, Procedimento internal.check_data_type_value, Linha 22 [Linha Inicial do Lote 0] O tipo de dados do valor de entrada não é compatível com o tipo de dados do 'Int64'.

Eu também tive outros erros para datetime e boolean

Portanto, sem se esforçar muito para entender o problema, a solução era basicamente usar um tipo de dados específico, e não sql_variantao passar um valor para o @valueparâmetro.

Para Int64 e Boolean, você pode apenas codificar o valor, mas datetimeé necessário declarar previamente uma variável do tipo datetimee usá-la - você não pode simplesmente passar um literal de data da string

Esta é a primeira vez que vi um parâmetro em um procedimento armazenado aparentemente aceitar uma variedade de tipos de dados.

DECLARE @var sql_variant
DECLARE @var_int int

SET @var = '2'
IF NOT EXISTS (
    SELECT 1 FROM [catalog].[environment_variables] 
    WHERE environment_id = @environment_id 
    AND name = N'MyVariable')
EXEC [catalog].[create_environment_variable] 
    @variable_name=N'SystemCd', 
    @sensitive=0, @description=N'', 
    @environment_name=@env_name, 
    @folder_name=@folder, 
    @value=@var_int, 
    @data_type=N'Int64'
Nick.McDermaid
fonte
Faz grande sentido de ser explícito em vez de usar as one-size-fits-all-de-SQL-Server-2000
billinkc