1

ActiveDirectoryからローカルアプリケーションデータベースにユーザーを同期する手順を作成しようとしています。私のコードから、次の形式のXMLをストアドプロシージャに渡します。

<AdUsers>
  <AdUser AccountSid="S-1-5-21-111111111-111111111-111111111-1111" DisplayName="Test User" EmailAddress="tuser@mail.local" ExchangeServerFk="4" ExchangeServer="https://mail.local" Department="" StatusFK="1" UserName="TUSER">
    <AccountSids>
      <Sid>S-1-5-21-111111111-111111111-111111111-1111</Sid>
    </AccountSids>
  </AdUser>
</AdUsers>

次のストアドプロシージャを使用して、XMLとtb_Mailboxesテーブルの行を同期したいと思います。

@adUsers XML, @lastSyncBy VARCHAR (50), @lastSyncOn DATETIME, @defaultProfileId INT, @adDomainId INT
AS

begin try
    BEGIN TRANSACTION
        --First delete all the mailboxes exist in the database but not in the xml.
        delete tb_Mailboxes
        where AccountSid not in (
            select 
                 rtrim(element.value('text()[1]', 'varchar(100)')) as AccountSid
            from 
                @adUsers.nodes('/AdUsers/AdUser/AccountSids/Sid') t(element)


        ) AND @adDomainId = AdDomainFk

        --Then insert or update existing accounts
        MERGE tb_Mailboxes as [target]
        USING 
        (
            select 
                 rtrim(element.value('data(@AccountSid)', 'varchar(100)')) as AccountSid
                ,rtrim(element.value('data(@DisplayName)', 'varchar(100)')) as DisplayName
                ,rtrim(element.value('data(@EmailAddress)', 'varchar(500)')) as EmailAddress
                ,rtrim(element.value('data(@ExchangeServerFk)', 'varchar(100)')) as ExchangeServerFk
                ,rtrim(element.value('data(@ExchangeServer)', 'varchar(150)')) as ExchangeServer
                ,rtrim(element.value('data(@Department)', 'varchar(100)')) as Department
                ,rtrim(element.value('data(@StatusFK)', 'varchar(100)')) as StatusFK
                ,rtrim(element.value('data(@UserName)', 'varchar(100)')) as UserName
                ,element.query('AccountSids') as SidList
            from 
                @adUsers.nodes('/AdUsers/AdUser') t(element)
        ) as [source] 
             on [target].AccountSid IN
             (
                SELECT rtrim(A.value('text()[1]', 'varchar(100)')) as CurSid 
                FROM [source].SidList.nodes('Sid') AS FN(A)
             )
        WHEN MATCHED THEN UPDATE SET
            DisplayName = [source].DisplayName
            ,EmailAddress = [source].EmailAddress
            ,ExchangeServerFk = [source].ExchangeServerFk
            ,ExchangeServer = [source].ExchangeServer
            ,Department = [source].Department
            ,UserName = [source].UserName   
            /*,StatusFK = [source].StatusFK*/
            ,LastSyncOn = @lastSyncOn
            ,LastSyncBy = @lastSyncBy
        WHEN NOT MATCHED THEN INSERT 
            (
                AdDomainFk, 
                UserName, 
                DisplayName, 
                Department, 
                EmailAddress, 
                ExchangeServerFk, 
                ExchangeServer, 
                AccountSid, 
                IsAutoDeleteEnabled, 
                ProfileFk, 
                Settings, 
                QueueLastPickedUp, 
                QueueLastProcessed, 
                QueueLastFinished, 
                LastSyncOn, 
                LastSyncBy,
                StatusFK
            )
            VALUES
            (
            @adDomainId
            ,[source].UserName
            ,[source].DisplayName
            ,[source].Department
            ,[source].EmailAddress
            ,[source].ExchangeServerFk
            ,[source].ExchangeServer
            ,[source].AccountSid
            ,0
            ,@defaultProfileId
            ,NULL
            ,NULL
            ,NULL
            ,NULL
            ,@lastSyncOn
            ,@lastSyncBy
            ,[source].StatusFK
            );

    COMMIT TRANSACTION
END TRY
BEGIN CATCH

    ROLLBACK TRANSACTION
END CATCH

ただし、削除セクションの「NOTIN」と一致セクションの「IN」は機能していないようです。XMLで複数の値を使用するこのタイプのIN句は実現可能ですか?私が見逃しているこの問題へのより良いアプローチはありますか?

4

1 に答える 1

1

MERGE クエリの問題は、[ソース] テーブルと [ターゲット] テーブルの間の結合です。を使用してターゲット テーブルとソース テーブルを結合するのではなく、

     ON [target].AccountSid IN
     (
        SELECT rtrim(A.value('text()[1]', 'varchar(100)')) as CurSid 
        FROM [source].SidList.nodes('Sid') AS FN(A)
     )

代わりにこれを使用してください:

    ON [target].AccountSid = [source].AccountSid

[source] はテーブルとして実体化され、他のテーブルと同じように結合します。IN ステートメントはまったく異なるエンティティであるため、あまり意味がありません。そのため、一種のデカルト結合 (FULL OUTER) と同等になります。

別のコメントとして、XML に存在しなくなったメールボックスを削除するために別の DELETE ステートメントを使用する理由を教えてください。次のステートメントを使用して、単純に MERGE ステートメント内に DELETE を入れてみませんか?

WHEN NOT MATCHED BY SOURCE 
               THEN DELETE

これらすべてを適用すると、MERGE ステートメントは次のようになります。

MERGE tb_Mailboxes AS [target]
    USING 
        (SELECT RTRIM(element.value('data(@AccountSid)', 'varchar(100)')) AS AccountSid
              , RTRIM(element.value('data(@DisplayName)', 'varchar(100)')) AS DisplayName
              , RTRIM(element.value('data(@EmailAddress)', 'varchar(500)')) AS EmailAddress
              , RTRIM(element.value('data(@ExchangeServerFk)', 'varchar(100)')) AS ExchangeServerFk
              , RTRIM(element.value('data(@ExchangeServer)', 'varchar(150)')) AS ExchangeServer
              , RTRIM(element.value('data(@Department)', 'varchar(100)')) AS Department
              , RTRIM(element.value('data(@StatusFK)', 'varchar(100)')) AS StatusFK
              , RTRIM(element.value('data(@UserName)', 'varchar(100)')) AS UserName
         FROM   @adUsers.nodes('/AdUsers/AdUser') t (element)) AS [source]
    ON [target].AccountSid = [source].AccountSid
    WHEN MATCHED 
        THEN UPDATE
           SET      DisplayName = [source].DisplayName
                  , EmailAddress = [source].EmailAddress
                  , ExchangeServerFk = [source].ExchangeServerFk
                  , ExchangeServer = [source].ExchangeServer
                  , Department = [source].Department
                  , UserName = [source].UserName   
        /*,StatusFK = [source].StatusFK*/
                  , LastSyncOn = @lastSyncOn
                  , LastSyncBy = @lastSyncBy
    WHEN NOT MATCHED BY TARGET
        THEN INSERT (AdDomainFk
                   , UserName
                   , DisplayName
                   , Department
                   , EmailAddress
                   , ExchangeServerFk
                   , ExchangeServer
                   , AccountSid
                   , IsAutoDeleteEnabled
                   , ProfileFk
                   , Settings
                   , QueueLastPickedUp
                   , QueueLastProcessed
                   , QueueLastFinished
                   , LastSyncOn
                   , LastSyncBy
                   , StatusFK)
           VALUES   (@adDomainId
                   , [source].UserName
                   , [source].DisplayName
                   , [source].Department
                   , [source].EmailAddress
                   , [source].ExchangeServerFk
                   , [source].ExchangeServer
                   , [source].AccountSid
                   , 0
                   , @defaultProfileId
                   , NULL
                   , NULL
                   , NULL
                   , NULL
                   , @lastSyncOn
                   , @lastSyncBy
                   , [source].StatusFK)
     WHEN NOT MATCHED BY SOURCE 
         THEN DELETE;   
于 2013-04-11T23:21:25.350 に答える