SSIS 2012 Tworzenie zmiennej środowiskowej kończy się niepowodzeniem

12

Pracuję w skrypcie, aby przenieść środowisko z jednego serwera na drugi. catalog.create_environment_variableWystępuje problem z wywołaniem, w którym pojawia się błąd „Typ danych wartości wejściowej nie jest zgodny z typem danych ciągu”. wychodzący z proc "check_data_type_value."

Dziwne jest to, że jeśli pozwolę skryptowi GUI wyliczyć zmienne, to zapytanie zadział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

Jednak takie podejście skryptowe nie działa. Praca, którą wykonałem, wskazuje, że ten komunikat o błędzie jest zazwyczaj rozwiązany przy użyciu typu danych nvarchar zamiast varchar. Nie dotyczy to jednak moich rzeczy.

Wiersz 108 dla następującego skryptu. Zakładam, że jest to coś dziwnego z sql_variant, ale nie mam pojęcia, co to jest.

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
źródło
7
Syn. Jestem rozczarowany
swasheck
5
@swasheck Czy zdajesz sobie sprawę, ile dumy pochłonęło, zanim mogłem kliknąć przycisk Prześlij?
billinkc
Nie znikam, właśnie uratowałeś mi noc. Freaking nVarChar
RThomas

Odpowiedzi:

10

„Praca, którą wykonałem, wskazuje, że ten komunikat o błędzie jest zazwyczaj rozwiązywany przez użycie typu danych nvarchar zamiast varchar. Jednak nie dotyczy to moich rzeczy”. A może tak jest ?

Wprowadziłem dwie zmiany w moim kursorze. Pierwszy jest w moim bloku CATCH. Ponownie przeczytałem artykuł na temat typu danych sql_variant i podążyłem za nim właściwość sql_variant_property . Dodałem wywołanie do tego w moim bloku catch, spodziewając się, że zobaczę, nvarcharale oto raportuje się varcharjako mój BaseType.

Wiedząc o tym i że wszystkie moje dane źródłowe są oparte na znakach, oszukałem i dodałem @localzmienną z wyraźną obsadą do nvarchar i to działa magicznie.

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;

Analiza przyczyn

Gdy zacząłem pisać podsumowanie ustaleń, odkryłem rozłączenie. Podczas ładowania tabeli tymczasowej @EnvironmentVariables pierwotnie pozyskałem ją bezpośrednio z catalog.environment_variables.Aby uczynić ją bardziej przenośną, skopiowałem wartości jako instrukcje SELECT. Właśnie to spieprzyłem. Kiedy odtworzyłem te wartości, przekształciłem ciągi Unicode w ciągi „mercan”. Zostały one zapisane w kolumnie typu sql_variant jako nie Unicode, które następnie wysadziły w powietrze, gdy zostały przekazane do proc w celu sprawdzenia poprawności. Jeśli poprawnie poprzedzę moje ciągi Nmodyfikatorem (?), Są one zapisywane jako 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
źródło
Użyłem wariantu tego thefirstsql.com/2013/05/28/... do wygenerowania mojego skryptu /. Jeśli dobrze rozumiem, muszę upewnić się, że wszystkie moje literały ciągów zaczynają się od, Nale nadal mam ten problem. W rzeczywistości dostaję skargi dotyczące wartości logicznej i daty i godziny, ale żaden z moich parametrów nie używa typów danych hetese. Czy masz jakiś wgląd?
Nick.McDermaid
1

Wystarczy dodać do @billinkc doskonałą odpowiedź (na pewno wiedziałeś, że to ty odpowiesz na to pytanie !!) i wzbogacić wiedzę wokół tego ....

Oto przykładowy kod, automatycznie generowany stąd https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/, który zgłasza błąd :

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'

W szczególności jest to błąd

Msg 27147, poziom 16, stan 1, procedura Internal.check_data_type_value, wiersz 22 [Batch Start Line 0] Typ danych wartości wejściowej nie jest zgodny z typem danych „Int64”.

Miałem także inne błędy dotyczące datetime i boolean

Bez dokładnego zrozumienia problemu rozwiązaniem było raczej użycie określonego typu danych niż sql_variantprzekazywanie wartości do @valueparametru.

Dla Int64 oraz logiczne można po prostu ciężko kodem wartość ale datetimety masz wstępnie zadeklarować zmienną typu datetimei używać go - nie można po prostu przejść się datę ciąg dosłownym

To jest pierwszy raz, kiedy zobaczyłem parametr w procedurze przechowywanej, najwyraźniej akceptujący różne typy danych.

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
źródło
Ma sens, aby być jawnym zamiast używać jednego rozmiaru dla wszystkich z SQL-Server-2000
billinkc