1

T-Sql の Merge ステートメントを使用して、最適化された緩やかに変化するディメンションを構築しようとしています。SCD1 と SCD2 の変更、およびデータ テーブルへの通常の挿入を処理する次のコードを作成しました。データはソース テーブルから取得され、Name と Age は SCD1 列、Animal と Blood は SCD2 列です。

DECLARE @LoadingDate DATETIME
SET @LoadingDate = '2012-08-20 14:23:29.827'

--Handle SCD1 Changes
MERGE INTO Table_2 AS DIM
 USING SourceTable AS SRC
 ON (DIM.ID1 = SRC.ID1
    AND DIM.ID2 = SRC.ID2)
 WHEN MATCHED
    AND (DIM.Name <> SRC.Name 
      OR DIM.AGE <> SRC.AGE)
    THEN 
    UPDATE 
    SET DIM.Name = SRC.Name,
    DIM.Age = SRC.Age;

--Handle SCD2 Changes
INSERT INTO Table_2
    (ID1, ID2, --Business Key
     Name, Age, --SCD1 Columns
     Animal, Blood, --SCD2 Columns
     DateEffective, DateExpires)
 SELECT
    ID1, ID2, --Business Key
     Name, Age, --SCD1 Columns
     Animal, Blood, --SCD2 Columns
     DateEffective, DateExpires
FROM (
MERGE Table_2 AS DIM
 USING SourceTable AS SRC
 ON (DIM.ID1 = SRC.ID1
    AND DIM.ID2 = SRC.ID2)
 WHEN NOT MATCHED
  THEN INSERT VALUES 
  (SRC.ID1, SRC.ID2,
   SRC.Name, SRC.Age,
   SRC.Animal, SRC.Blood,
   @LoadingDate, NULL)
 WHEN MATCHED 
   AND DIM.DateExpires IS NULL
   AND (DIM.Animal != SRC.Animal
    OR DIM.Blood != SRC.Blood)
   THEN UPDATE SET DIM.DateExpires = @LoadingDate
 OUTPUT $action Action_Out,
   SRC.ID1, SRC.ID2,
   SRC.Name, SRC.Age,
   SRC.Animal, SRC.Blood,
   @LoadingDate AS DateEffective,
   NULL AS DateExpires) AS MERGE_OUT
 WHERE MERGE_OUT.Action_Out = 'UPDATE';

コードは SCD1 の変更 (コードの最初の部分) で正常に動作しますが、エラー が発生します。ここに画像の説明を入力 ビジネス キー ID1 と ID2 が他の行と一致しない新しい行を挿入しようとすると、エラーが表示されます。 「Labus」は名前フィールドの値です。

どちらのテーブルも次の図のように設計されていますが、SourceTable にはハウスキーピング列がありません。 ここに画像の説明を入力

助けていただければ幸いです。ありがとう!

4

3 に答える 3

1

このエラーは、暗黙的な nvarchar から int への変換が間違っていることを示唆しているため、これをトラブルシューティングするための最初の手順は、可能なすべての nvarchar および int 値を明示的にキャストし (以下に示すように)、引き続きエラーが発生するかどうかを確認することです。

エラーが発生しない場合は、キャストの削除を開始し、特定の int または nvarchar フィールドにゼロインできます。

エラーが発生した場合、これはより具体的なエラーである可能性があり、コードのどのセクションで発生しているかを把握するのに役立ちます。

DECLARE @LoadingDate DATETIME
SET @LoadingDate = '2012-08-20 14:23:29.827'

--Handle SCD1 Changes
MERGE INTO Table_2 AS DIM
    USING SourceTable AS SRC
    ON ( CAST(DIM.ID1 AS INT) = CAST(SRC.ID1 AS INT)
         AND CAST(DIM.ID2 AS INT) = CAST(caSSRC.ID2 AS INT)
       )
    WHEN MATCHED AND ( CAST(DIM.Name AS nvarchar(255)) <> CAST(SRC.Name AS nvarchar(255))
                       OR CAST(DIM.AGE AS nvarchar(255)) <> CAST(SRC.AGE AS nvarchar(255))
                     )
        THEN 
    UPDATE
          SET
            DIM.Name = CAST(SRC.Name AS nvarchar(255)) ,
            DIM.Age = CAST(SRC.Age AS nvarchar(255)) ;

--Handle SCD2 Changes
INSERT  INTO Table_2
        ( ID1 ,
          ID2 , --Business Key
          Name ,
          Age , --SCD1 Columns
          Animal ,
          Blood , --SCD2 Columns
          DateEffective ,
          DateExpires
        )
        SELECT  CAST(ID1 AS INT),
                CAST(ID2 AS INT) , --Business Key
                CAST(Name AS nvarchar(255)) ,
                CAST(Age AS nvarchar(255)) , --SCD1 Columns
                CAST(Animal AS nvarchar(255)) ,
                CAST(Blood AS nvarchar(255)) , --SCD2 Columns
                DateEffective ,
                DateExpires
        FROM    (
MERGE Table_2 AS DIM
    USING SourceTable AS SRC
    ON ( CAST(DIM.ID1 AS INT) = CAST(SRC.ID1 AS INT)
         AND CAST(DIM.ID2 AS INT) =  CAST(SRC.ID2 AS INT)
       )
    WHEN NOT MATCHED 
        THEN INSERT
          VALUES    ( CAST(SRC.ID1 AS INT) ,
                      CAST(SRC.ID2 AS INT) ,
                  CAST(SRC.Name AS NVARCHAR(255)),
                  CAST(SRC.Age AS NVARCHAR(255)),
                  CAST(SRC.Animal AS NVARCHAR(255)),
                  CAST(SRC.Blood  AS NVARCHAR(255)),
                      @LoadingDate ,
                      NULL
                    )
    WHEN MATCHED AND DIM.DateExpires IS NULL
        AND ( CAST(DIM.Animal AS NVARCHAR(255)) != CAST(SRC.Animal AS NVARCHAR(255))
              OR CAST(DIM.Blood AS NVARCHAR(255)) != CAST(SRC.Blood AS NVARCHAR(255))
            )
        THEN UPDATE
          SET       DIM.DateExpires = @LoadingDate
    OUTPUT
        $action Action_Out ,
        SRC.ID1 ,
        SRC.ID2 ,
        SRC.Name ,
        SRC.Age ,
        SRC.Animal ,
        SRC.Blood ,
        @LoadingDate AS DateEffective ,
        NULL AS DateExpires) AS MERGE_OUT
        WHERE   MERGE_OUT.Action_Out = 'UPDATE' ;
    --...
    --...
    --...
于 2012-08-20T14:31:56.617 に答える
0

あっ、待って!最後のマージの OUTPUT は、Select 句と一致しない場合があります。したがって、Action_Out が ID1 にマップされる可能性があるため、暗黙的な変換が試行されます。

次のように OUTPUT 句を変更してみてください。

OUTPUT
    $action Action_Out ,
    SRC.ID1 AS ID1,
    SRC.ID2 AS ID2,
    SRC.Name AS Name,
    SRC.Age AS Age,
    SRC.Animal AS Animal,
    SRC.Blood AS Blood,
    @LoadingDate AS DateEffective ,
    NULL AS DateExpires) AS MERGE_OUT
    WHERE   MERGE_OUT.Action_Out = 'UPDATE' ; 
于 2012-08-20T14:43:26.340 に答える
0

これを試してください: 基本的に、SELECT 列でエイリアスを使用しました。
(コンポーザブル DML にはまだ改善の余地があります。)

また、サブクエリで既に Merge into Table_2 を実行しているときに、追加のレコード (更新アクション用) を再度 Table_2 に挿入する理由はありますか?

DECLARE @LoadingDate DATETIME
SET @LoadingDate = '2012-08-20 14:23:29.827'

--Handle SCD1 Changes
MERGE INTO Table_2 AS DIM
    USING SourceTable AS SRC
    ON ( DIM.ID1 = SRC.ID1
         AND DIM.ID2 = SRC.ID2
       )
    WHEN MATCHED AND ( DIM.Name <> SRC.Name
                       OR DIM.AGE <> SRC.AGE
                     )
        THEN 
    UPDATE
          SET
            DIM.Name = SRC.Name ,
            DIM.Age = SRC.Age ;

--Handle SCD2 Changes
INSERT  INTO Table_2
        ( ID1 ,
          ID2 , --Business Key
          Name ,
          Age , --SCD1 Columns
          Animal ,
          Blood , --SCD2 Columns
          DateEffective ,
          DateExpires
        )
        SELECT  MERGE_OUT.ID1 ,
                MERGE_OUT.ID2 , --Business Key
                MERGE_OUT.Name ,
                MERGE_OUT.Age , --SCD1 Columns
                MERGE_OUT.Animal ,
                MERGE_OUT.Blood , --SCD2 Columns
                MERGE_OUT.DateEffective ,
                MERGE_OUT.DateExpires
        FROM    (
MERGE INTO Table_2 AS DIM
    USING SourceTable AS SRC
    ON ( DIM.ID1 = SRC.ID1
         AND DIM.ID2 = SRC.ID2
       )
    WHEN NOT MATCHED 
        THEN INSERT
          VALUES    ( SRC.ID1 ,
                      SRC.ID2 ,
                      SRC.Name ,
                      SRC.Age ,
                      SRC.Animal ,
                      SRC.Blood ,
                      @LoadingDate ,
                      NULL
                    )
    WHEN MATCHED AND DIM.DateExpires IS NULL
        AND ( DIM.Animal != SRC.Animal
              OR DIM.Blood != SRC.Blood
            )
        THEN UPDATE
          SET       DIM.DateExpires = @LoadingDate
    OUTPUT
        $action AS Action_Out ,
        SRC.ID1 AS ID1 ,
        SRC.ID2 AS ID2 ,
        SRC.NAME AS Name ,
        SRC.Age AS Age ,
        SRC.Animal AS Animal ,
        SRC.Blood AS Blood ,
        @LoadingDate AS DateEffective ,
    NULL AS DateExpires) AS MERGE_OUT ( ID1, ID2, Name, Age, Animal, Blood,
                                        DateEffective, DateExpires )
        WHERE   MERGE_OUT.Action_Out = 'UPDATE' ;
于 2012-08-21T15:01:03.587 に答える