SSIS 2012 สร้างตัวแปรสภาพแวดล้อมล้มเหลว


12

ฉันกำลังทำงานสคริปต์เพื่อพอร์ตสภาพแวดล้อมจากเซิร์ฟเวอร์หนึ่งไปยังเซิร์ฟเวอร์อื่น ฉันพบปัญหาในการโทรติดต่อcatalog.create_environment_variableเพื่อรับข้อผิดพลาด "ประเภทข้อมูลของค่าอินพุตไม่เข้ากันกับประเภทข้อมูลของ 'String' ออกมาจาก proc "check_data_type_value"

สิ่งที่แปลกคือถ้าฉันปล่อยให้สคริปต์ GUI ออกตัวแปรแบบสอบถามนั้นจะใช้ได้

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

อย่างไรก็ตามการใช้วิธีการสคริปต์นี้ไม่ทำงาน legwork ที่ฉันทำบ่งชี้ว่าข้อความแสดงข้อผิดพลาดนี้มักแก้ไขโดยใช้ชนิดข้อมูล nvarchar แทน varchar อย่างไรก็ตามนั่นไม่ใช่กรณีสำหรับสิ่งของของฉัน

บรรทัดที่ 108 สำหรับสคริปต์ต่อไปนี้ สมมติฐานของฉันคือว่ามันเป็นสิ่งที่ wonky กับsql_variantแต่ผมไม่มีความคิดสิ่งที่สิ่งที่เป็น

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
ลูกชาย. ฉันผิดหวัง
swasheck

5
@swasheck คุณรู้ไหมว่าความภาคภูมิใจถูกกลืนกินไปนานแค่ไหนก่อนที่ฉันจะคลิกปุ่มส่ง?
billinkc

ฉันไม่ได้แยกคุณแค่ช่วยชีวิตฉันไว้ Freaking nVarChar
RThomas

คำตอบ:


10

"legwork ที่ฉันทำบ่งชี้ว่าข้อความแสดงข้อผิดพลาดนี้มักจะได้รับการแก้ไขโดยใช้ชนิดข้อมูล nvarchar แทนที่จะเป็น varchar อย่างไรก็ตามนั่นไม่ใช่สิ่งที่ฉันต้องการ" หรือเป็นกรณี?

ฉันทำการเปลี่ยนแปลงเคอร์เซอร์สองครั้ง สิ่งแรกคือในบล็อกของฉัน ฉันอีกครั้งอ่านบทความเกี่ยวกับชนิดข้อมูล sql_variant และตามด้วยsql_variant_property ฉันได้เพิ่มการเรียกไปยังสิ่งนั้นใน catch catch ของฉันโดยคาดว่าจะเห็นnvarcharแต่แท้จริงแล้วดูเถิดรายงานกลับvarcharเป็น BaseType ของฉัน

เมื่อรู้ว่าและแหล่งข้อมูลทั้งหมดของฉันนั้นเป็นแบบตัวละครฉันก็โกงและเพิ่ม@localตัวแปรด้วยการส่งไปยัง nvarchar อย่างชัดเจนและมันใช้งานได้อย่างมหัศจรรย์

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;

การวิเคราะห์สาเหตุที่แท้จริง

เมื่อฉันเริ่มเขียนบทสรุปของข้อค้นพบฉันค้นพบสิ่งที่ตัดการเชื่อมต่อ ขณะที่ฉันกำลังโหลดตารางชั่วคราวของฉัน @EnvironmentVariables ฉันได้มาจากที่โดยตรงcatalog.environment_variables.เพื่อทำให้เป็นแบบพกพามากขึ้นฉันคัดลอกค่าออกเป็นคำสั่ง SELECT นี่คือที่ฉันเมา เมื่อฉันสร้างค่าเหล่านั้นขึ้นมาใหม่ฉันสร้างสตริง Unicode ให้เป็น 'สายปรอท พวกเขาถูกเขียนลงในคอลัมน์ประเภท sql_variant เป็น non-unicode ซึ่งจะระเบิดเมื่อมันถูกส่งผ่านใน proc สำหรับการตรวจสอบ หากฉันนำหน้าสตริงของฉันอย่างถูกต้องด้วยโมดิNฟายเออร์ (?) จะถูกเก็บเป็น 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)

ฉันใช้ตัวแปรของthefirstsql.com/2013/05/28/…นี้เพื่อสร้างสคริปต์ของฉัน / ถ้าฉันเข้าใจถูกต้องฉันต้องแน่ใจว่าตัวอักษรสตริงทั้งหมดของฉันเริ่มต้นด้วยNแต่ฉันยังคงมีปัญหานี้อยู่ อันที่จริงฉันได้รับการร้องเรียนเกี่ยวกับบูลีนและ datetime แต่ไม่มีพารามิเตอร์ของฉันใช้ชนิดข้อมูล htese คุณมีความเข้าใจด้านใดบ้าง?
Nick.McD เงือก

1

เพียงเพิ่ม @billinkc คำตอบที่ยอดเยี่ยม (แน่นอนคุณรู้ว่าคุณจะเป็นหนึ่งในการตอบคำถามนี้ !!) และเสริมความรู้รอบนี้ ....

นี่คือบางส่วนโค้ดตัวอย่าง autogenerated จากที่นี่https://thefirstsql.com/2013/05/28/ssis-2012-easily-copy-environment-variables-to-new-servers-or-new-environments/ที่พ่นข้อผิดพลาด :

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'

ข้อผิดพลาดโดยเฉพาะคือ

ข่าวสารเกี่ยวกับ 27147, ระดับ 16, สถานะ 1, กระบวนงาน internal.check_data_type_value, บรรทัดที่ 22 [Batch Start Line 0] ประเภทข้อมูลของค่าอินพุตไม่เข้ากันกับชนิดข้อมูลของ 'Int64'

ฉันยังมีข้อผิดพลาดอื่น ๆ สำหรับ datetime และบูลีน

ดังนั้นโดยไม่ต้องทำความเข้าใจปัญหาเป็นระยะเวลานานวิธีการแก้ปัญหาก็คือการใช้ประเภทข้อมูลที่เฉพาะเจาะจงมากกว่าsql_variantเมื่อส่งค่าลงใน@valueพารามิเตอร์

สำหรับ Int64 และ Boolean คุณสามารถกำหนดค่าได้ยาก แต่datetimeคุณต้องประกาศตัวแปรประเภทdatetimeและใช้มันล่วงหน้าคุณไม่สามารถส่งผ่านวันที่ของสตริงได้

นี่เป็นครั้งแรกที่ฉันเห็นพารามิเตอร์ในกระบวนงานที่เก็บไว้ยอมรับว่ามีชนิดข้อมูลที่หลากหลาย

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'

ทำให้รู้สึกดีอย่างชัดเจนแทนที่จะใช้ one-size-fits-all-from-SQL-Server-2000
billinkc
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.