SSIS 2012 La creazione della variabile di ambiente non riesce


12

Sto lavorando uno script per il porting di un ambiente da un server a un altro. Sto riscontrando un problema in catalog.create_environment_variablecui viene visualizzato l'errore "Il tipo di dati del valore di input non è compatibile con il tipo di dati di" String "." uscendo dal proc "check_data_type_value".

La cosa strana è che se lascio che lo script GUI esca dalle variabili, quella query funzionerebbe

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

Tuttavia, adottare questo approccio di script non funziona. La legwork che ho fatto indica che questo messaggio di errore viene in genere risolto utilizzando il tipo di dati nvarchar anziché varchar. Tuttavia, non è il caso delle mie cose.

Riga 108 per il seguente script. La mia ipotesi è che sia qualcosa di strano con sql_variant ma non ho idea di cosa sia quella 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;

7
Figlio. Sono deluso.
sweckeck,

5
@swasheck Ti rendi conto di quanto orgoglio è stato ingoiato prima che potessi fare clic sul pulsante Invia?
billinkc,

Non sto disapprovando, mi hai appena salvato la notte. Freaking nVarChar
RThomas

Risposte:


10

"La legwork che ho fatto indica che questo messaggio di errore è in genere risolto utilizzando il tipo di dati nvarchar invece di varchar. Tuttavia, non è il caso delle mie cose." O è il caso?

Ho apportato due modifiche al mio cursore. Il primo è nel mio blocco CATCH. Ho riletto l'articolo sul tipo di dati sql_variant e seguito con sql_variant_property . Ho aggiunto una chiamata a quella nel mio blocco catch, aspettandomi di vedere nvarcharma ecco ed ecco, riporta varcharcome il mio BaseType.

Sapendo che e tutti i miei dati di origine sono basati sui caratteri, ho tradito e aggiunto la @localvariabile con un cast esplicito a nvarchar e funziona 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;

Analisi della causa principale

Quando ho iniziato a scrivere un riepilogo dei risultati, ho scoperto la disconnessione. Mentre stavo caricando la mia tabella temporanea, @EnvironmentVariables, originariamente l'avevo acquisito direttamente da catalog.environment_variables.Per renderlo più portatile, ho copiato i valori come istruzioni SELECT. Questo è dove ho rovinato tutto. Quando ho ricostituito quei valori, ho trasformato le stringhe Unicode in stringhe di mercan. Sono stati scritti nella colonna di tipo sql_variant come non unicode che poi è esploso quando è stato passato nel proc per la convalida. Se eseguo correttamente la prefazione delle mie stringhe con il Nmodificatore (?) Sono memorizzate come 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)

Ho usato una variante di questo thefirstsql.com/2013/05/28/… per generare il mio script /. Se capisco correttamente, devo assicurarmi che tutti i miei letterali stringa inizino con Nma ho ancora questo problema. In effetti ricevo lamentele su booleano e datetime ma nessuno dei miei parametri utilizza questi tipi di dati. Hai qualche intuizione?
Nick.McDermaid,

1

Solo per aggiungere alla risposta eccellente di @billinkc (sicuramente sapevi che saresti stato tu a rispondere a questa domanda !!) e arricchire la conoscenza intorno a questo ....

Ecco alcuni esempi di codice, generati automaticamente da qui https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/ che genera l'errore :

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'

In particolare l'errore è

Messaggio 27147, livello 16, stato 1, procedura internal.check_data_type_value, riga 22 [Batch Start Line 0] Il tipo di dati del valore di input non è compatibile con il tipo di dati di "Int64".

Ho anche avuto altri errori per datetime e booleano

Quindi, senza approfondire la comprensione del problema, la soluzione consisteva essenzialmente nell'utilizzare un tipo di dati specifico anziché sql_variantpassare un valore nel @valueparametro.

Per Int64 e booleana è possibile codificare solo difficile, ma il valore per datetimevoi avete pre dichiarare una variabile di tipo datetimee usarlo - non si può semplicemente passare in una data stringa letterale

Questa è la prima volta che vedo un parametro in una procedura memorizzata apparentemente accettare una varietà di tipi di dati.

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'

Ha molto senso essere esplicito invece di usare il one-size-fits-all-from-SQL-Server-2000
billinkc,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.