SSIS 2012 Crear variable de entorno falla

12

Estoy trabajando un script para portar un entorno de un servidor a otro. Me encuentro con un problema de llamada catalog.create_environment_variableen el que aparece el error "El tipo de datos del valor de entrada no es compatible con el tipo de datos de la 'Cadena'". saliendo del proceso "check_data_type_value".

Lo que es extraño es que si dejo que la secuencia de comandos GUI elimine las variables, esa consulta funcionaría

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

Sin embargo, adoptar este enfoque de script no funciona. El trabajo preliminar que he hecho indica que este mensaje de error generalmente se resuelve usando el tipo de datos nvarchar en lugar de varchar. Sin embargo, ese no es el caso de mis cosas.

Línea 108 para el siguiente guión. Mi suposición es que es algo inestable con la variante sql_ pero no tengo idea de qué es esa cosa.

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
fuente
77
Hijo. Estoy decepcionado
swasheck
55
@swasheck ¿Te das cuenta de cuánto orgullo se tragó antes de que pudiera hacer clic en el botón Enviar?
billinkc
No estoy decepcionado, acabas de salvar mi noche. Freaking nVarChar
RThomas

Respuestas:

10

"El trabajo preliminar que hice indica que este mensaje de error generalmente se resuelve usando el tipo de datos nvarchar en lugar de varchar. Sin embargo, ese no es el caso para mis cosas". ¿O es el caso?

Hice dos cambios en mi cursor. El primero está en mi bloque CATCH. Volví a leer el artículo sobre el tipo de datos sql_variant y seguí con la propiedad sql_variant_property . Agregué una llamada a eso en mi bloque catch, esperando ver nvarcharpero he aquí, informa varcharcomo mi BaseType.

Sabiendo eso y que todos mis datos fuente están basados ​​en caracteres, hice trampa y agregué la @localvariable con un reparto explícito a nvarchar y funciona mágicamente.

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álisis de raíz de la causa

Cuando comencé a escribir un resumen de hallazgos, descubrí la desconexión. Cuando estaba cargando mi tabla temporal, @EnvironmentVariables, originalmente la obtuve directamente de catalog.environment_variables.Para hacerla más portátil, copié los valores como sentencias SELECT. Aquí es donde lo arruiné. Cuando reconstituí esos valores, convertí las cadenas Unicode en 'cadenas mercan. Se escribieron en la columna de tipo sql_variant como no unicode que luego explotó cuando se pasó en el proceso para la validación. Si presento correctamente mis cadenas con el Nmodificador (?), Se almacenan 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
fuente
Usé una variante de esto thefirstsql.com/2013/05/28/… para generar mi script /. Si entiendo correctamente, necesito asegurarme de que todos mis literales de cadena comiencen Npero todavía tengo este problema. De hecho, recibo quejas sobre boolean y datetime, pero ninguno de mis parámetros usa tipos de datos htese. ¿Tienes alguna idea?
Nick.McDermaid
1

Solo para agregar a @billinkc una excelente respuesta (¡seguramente sabías que serías el que respondería esta pregunta!) Y enriquecerás el conocimiento sobre esto ...

Aquí hay un código de muestra, generado automáticamente desde aquí https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/ que arroja el error :

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'

Específicamente el error es

Msg 27147, Nivel 16, Estado 1, Procedimiento internal.check_data_type_value, Línea 22 [Batch Start Line 0] El tipo de datos del valor de entrada no es compatible con el tipo de datos de 'Int64'.

También tuve otros errores para datetime y boolean

Entonces, sin hacer un gran esfuerzo para comprender el problema, la solución fue básicamente usar un tipo de datos específico en lugar de sql_variantpasar un valor al @valueparámetro.

Para Int64 y booleano que puede codificar sólo difícil, pero el valor para el datetimeque tiene de comprobar la validez declarar una variable de tipo datetimey usarlo - no se puede simplemente pasar en un literal de cadena fecha

Esta es la primera vez que veo un parámetro en un procedimiento almacenado que aparentemente acepta una variedad de tipos de datos.

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
fuente
Tiene mucho sentido ser explícito en lugar de usar el tamaño único para todos de SQL-Server-2000
billinkc