SSIS 2012 Membuat variabel lingkungan gagal

12

Saya sedang mengerjakan skrip untuk mem-port suatu Lingkungan dari satu server ke server lainnya. Saya mengalami masalah saat memanggil di catalog.create_environment_variablemana saya mendapatkan kesalahan "Tipe data dari nilai input tidak kompatibel dengan tipe data dari 'String'." keluar dari proc "check_data_type_value."

Yang aneh adalah bahwa jika saya membiarkan skrip GUI keluar variabel, kueri itu akan berfungsi

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

Namun, mengambil pendekatan skrip ini tidak berfungsi. Pekerjaan yang saya lakukan menunjukkan pesan kesalahan ini biasanya diselesaikan dengan menggunakan tipe data nvarchar, bukan varchar. Namun, bukan itu yang terjadi pada barang-barangku.

Baris 108 untuk skrip berikut. Asumsi saya adalah bahwa itu sesuatu yang tidak beres dengan sql_variant tapi saya tidak tahu apa itu.

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
sumber
7
Putra. Saya kecewa.
swasheck
5
@swasheck Apakah Anda menyadari betapa banyak kebanggaan ditelan sebelum saya bisa mengklik tombol Kirim?
billinkc
Saya tidak setuju, Anda baru saja menyelamatkan malam saya. Freaking nVarChar
RThomas

Jawaban:

10

"Pekerjaan keras yang telah saya lakukan menunjukkan pesan kesalahan ini biasanya diselesaikan dengan menggunakan tipe data nvarchar alih-alih varchar. Namun, bukan itu yang terjadi pada barang-barang saya." Atau apakah ini masalahnya?

Saya membuat dua perubahan pada kursor saya. Yang pertama ada di blok CATCH saya. Saya membaca kembali artikel tentang tipe data sql_variant dan diikuti dengan sql_variant_property . Saya menambahkan panggilan untuk itu di blok tangkap saya, berharap untuk melihat nvarchartetapi lihatlah, itu melaporkan kembali varcharsebagai BaseType saya.

Mengetahui itu dan bahwa semua data sumber saya berdasarkan karakter, saya menipu dan menambahkan @localvariabel dengan pemeran eksplisit ke nvarchar dan itu berfungsi secara ajaib.

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;

Analisis akar penyebab

Ketika saya mulai menulis ringkasan temuan, saya menemukan keterputusannya. Ketika saya sedang memuat tabel sementara saya, @EnvironmentVariables, saya awalnya bersumber langsung dari catalog.environment_variables.Agar lebih portabel, saya menyalin nilai-nilai sebagai pernyataan SELECT. Di sinilah saya mengacau. Ketika saya menyusun kembali nilai-nilai itu, saya membuat string Unicode menjadi string mercan. Mereka ditulis ke dalam kolom tipe sql_variant sebagai non-unicode yang kemudian meledak ketika disahkan di proc untuk validasi. Jika saya benar-benar mengawali string saya dengan Nmodifier (?) Mereka disimpan sebagai 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
sumber
Saya menggunakan varian thefirstsql.com/2013/05/28/… ini untuk menghasilkan skrip saya /. Jika saya mengerti dengan benar, saya perlu memastikan semua string literal saya mulai dengan Ntetapi saya masih memiliki masalah ini. Sebenarnya saya mendapatkan keluhan tentang boolean dan datetime tetapi tidak ada parameter saya yang menggunakan tipe data htese. Apakah Anda memiliki wawasan?
Nick.McDermaid
1

Hanya dengan menambahkan jawaban yang sangat bagus ke @billinkc (pasti Anda tahu Anda yang akan menjawab pertanyaan ini !!) dan memperkaya pengetahuan tentang hal ini ....

Berikut beberapa contoh kode, dibuat secara otomatis dari sini https://thefirstsql.com/2013/05/28/ssis-2012- dengan mudah- copy-environment-variables-to-new-servers-or-new-environmentments / yang melempar kesalahan :

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'

Secara khusus kesalahannya adalah

Msg 27147, Level 16, Status 1, Prosedur internal.check_data_type_value, Baris 22 [Baris Mulai Batch 0] Jenis data dari nilai input tidak kompatibel dengan tipe data dari 'Int64'.

Saya juga memiliki kesalahan lain untuk datetime dan boolean

Jadi tanpa berusaha keras untuk memahami masalah ini, solusinya pada dasarnya adalah menggunakan tipe data tertentu daripada sql_variantsaat memberikan nilai ke dalam @valueparameter.

Untuk Int64 dan Boolean Anda hanya dapat mengkodekan nilainya dengan keras, tetapi karena datetimeAnda harus terlebih dahulu mendeklarasikan variabel tipe datetimedan menggunakannya - Anda tidak bisa hanya memasukkan string tanggal literal

Ini adalah pertama kalinya saya melihat parameter dalam prosedur tersimpan tampaknya menerima berbagai tipe data.

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
sumber
Masuk akal untuk menjadi eksplisit daripada menggunakan one-size-fits-all-from-SQL-Server-2000
billinkc