SSIS 2012-Umgebungsvariable erstellen schlägt fehl


12

Ich arbeite an einem Skript, um eine Umgebung von einem Server auf einen anderen zu portieren. Beim Aufrufen eines Problems wird catalog.create_environment_variabledie Fehlermeldung "Der Datentyp des Eingabewerts ist nicht mit dem Datentyp der Zeichenfolge kompatibel" angezeigt. kommt aus dem proc "check_data_type_value".

Merkwürdig ist, dass diese Abfrage funktionieren würde, wenn ich das GUI-Skript die Variablen auslassen würde

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

Dieser Skriptansatz funktioniert jedoch nicht. Die von mir durchgeführten Vorarbeiten weisen darauf hin, dass diese Fehlermeldung normalerweise mithilfe des Datentyps nvarchar anstelle von varchar behoben wird. Für meine Sachen ist das jedoch nicht der Fall.

Zeile 108 für das folgende Skript. Ich gehe davon aus, dass es etwas Wackeliges mit der sql_variant ist, aber ich habe keine Ahnung, was das für ein Ding ist.

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
Sohn. Ich bin enttäuscht.
Swasheck

5
@swasheck Weißt du, wie viel Stolz geschluckt wurde, bevor ich auf die Schaltfläche "Senden" klicken konnte?
Billinkc

Ich bin nicht verschwunden, du hast mir gerade die Nacht gerettet. Freaking nVarChar
RThomas

Antworten:


10

"Die Arbeit, die ich gemacht habe, zeigt an, dass diese Fehlermeldung normalerweise mit dem Datentyp nvarchar anstelle von varchar behoben wird. Dies ist jedoch für meine Daten nicht der Fall." Oder ist es so?

Ich habe zwei Änderungen an meinem Cursor vorgenommen. Der erste befindet sich in meinem CATCH-Block. Ich las den Artikel über den Datentyp sql_variant noch einmal und folgte mit der Eigenschaft sql_variant_property . Ich habe einen Anruf , dass in meinem catch - Block, um zu sehen , erwartete nvarcharaber lo und siehe, es meldet zurück , varcharwie mein Basetype.

Da ich weiß, dass alle meine Quelldaten @localzeichenbasiert sind , habe ich die Variable betrogen und mit einer expliziten Umwandlung in nvarchar hinzugefügt, und sie funktioniert auf magische Weise.

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;

Ursachenanalyse

Als ich anfing, eine Zusammenfassung der Ergebnisse zu schreiben, entdeckte ich die Trennung. Als ich meine temporäre Tabelle, @EnvironmentVariables, lud, hatte ich diese ursprünglich direkt von übernommen. catalog.environment_variables.Um sie portabler zu machen, kopierte ich die Werte als SELECT-Anweisungen heraus. Dies ist, wo ich vermasselt habe. Bei der Wiederherstellung dieser Werte habe ich die Unicode-Zeichenfolgen in Mercan-Zeichenfolgen umgewandelt. Sie wurden als Nicht-Unicode in die Spalte vom Typ sql_variant geschrieben, die dann explodierte, als sie zur Validierung im proc übergeben wurden. Wenn ich meine Zeichenfolgen korrekt mit dem NModifikator (?) Vorstelle, werden sie als nvarchar gespeichert.

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)

Ich habe eine Variante dieses thefirstsql.com/2013/05/28/… verwendet , um mein script / zu generieren. Wenn ich das richtig verstehe, muss ich sicherstellen, dass alle meine String-Literale mit beginnen, Naber ich habe immer noch dieses Problem. Tatsächlich erhalte ich Beschwerden über Boolean und Datetime, aber keiner meiner Parameter verwendet diesen Datentyp. Hast du irgendwelche Einsichten?
Nick.McDermaid

1

Nur um @billinkc eine ausgezeichnete Antwort hinzuzufügen (Sie wussten doch, dass Sie die Antwort auf diese Frage sein würden !!) und das Wissen um diese Frage zu bereichern ...

Hier ist ein Beispielcode, der von hier aus automatisch generiert wurde https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/ , der den Fehler auslöst :

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'

Insbesondere ist der Fehler

Meldung 27147, Ebene 16, Status 1, Prozedur internal.check_data_type_value, Zeile 22 [Batch Start Line 0] Der Datentyp des Eingabewerts ist nicht kompatibel mit dem Datentyp des 'Int64'.

Ich hatte auch andere Fehler für datetime und boolean

Daher bestand die Lösung, ohne das Problem zu verstehen, darin, einen bestimmten Datentyp zu verwenden, anstatt sql_varianteinen Wert an den @valueParameter zu übergeben.

Für Int64 und Boolean können Sie nur den Wert harter Code , sondern für datetimeSie müssen vorab eine Variable vom Typ deklarieren datetimeund verwenden Sie es - Sie können nicht nur in einem String Datumsliteral passieren

Dies ist das erste Mal, dass ich einen Parameter in einer gespeicherten Prozedur sehe, der anscheinend eine Vielzahl von Datentypen akzeptiert.

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'

Es ist sehr sinnvoll, explizit zu sein, anstatt den One-Size-Fits-All-from-SQL-Server-2000 zu verwenden
billinkc
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.