2017-09-12 18 views
0

table AddressesにはID (PK), EmpID (int), Address (nvarchar(100), IsDefault (bit)の列があります。 同じEmpIDを持つレコードが1つだけIsDefaultが1に設定されていることを確認しなければなりません。 私は今トリガーで続けています。 最初は挿入トリガーです。まず、IsDefaultに値1が入力されているかどうかを確認します。 1に設定された同じEmpIDIsDefault値を持つより、その後のレコードがある場合にも真であるならば、はい、それはチェックしている場合、それは同じEmpID 0にするために、他のすべてのIsDefaultの値を設定します。1つのレコードに1を、他のすべてに0を設定する方法

create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_insert] 
    on [dbo].[lAddressesOrganisations] 
    after insert 
as 
begin 

    set nocount on; 

    begin try 

     if exists (
      select * 
      from inserted as i 
      where i.IsDefault = 1) 
     begin 

      if (
       select count(*) 
       from dbo.Addresses as lao 
       inner join inserted as i on i.ID=lao.ID 
       where lao.IsDefault = 1 
        and lao.EmpID = i.EmpID 
       ) > 1 
      begin 

       update lao 
       set lao.IsDefault = 0 
       from dbo.Addresses as lao 
       where (
        select row_number() over (partition by EmpID order by ID desc) as rn 
        from dbo.Addresses as lao 
       ) > 1 
      end 
     end 
    end try 

    begin catch 

     if @@trancount > 0 
      rollback tran; 

    end catch 

end 

このもう1つは更新トリガーであり、私はそれを書く方法を知らない。最初に挿入トリガーと同じことを行い、値が0であれば挿入された値を1にチェックします。値が0の場合は1であり、一致する場合はEmpIDおよびIsDefaultが1に設定されています。他のすべてのレコードは同じEmpIDの場合は0に設定されますが、更新中のレコードは1のままです。

create trigger [dbo].[TRG_dbo_Addresses_IsDefault_OnlyOneRecord_update] 
    on [dbo].[Addresses] 
    after update 
as 
begin 

    set nocount on; 

    begin try 

     if exists (
      select * 
      from inserted as i 
      inner join deleted as d on d.ID=i.ID 
      where i.IsDefault = 1 
       and d.IsDefault = 0) 
     begin 
      if (
       select count(*) 
       from dbo.Addresses as lao 
       inner join inserted as i on i.ID=lao.ID 
       where lao.IsDefault = 1 
        and lao.EmpID = i.EmpID 
       ) > 1 
      begin 
       update lao 
       set lao.IsDefault = 0 
       from dbo.Addresses as lao 
       inner join inserted as i on i.ID=lao.ID 
       where (I don't have an idea what to put here) 
        and lao.OrganisationID = i.OrganisationID 
      end 
     end 
    end try 

    begin catch 

     if @@trancount > 0 
      rollback tran; 

    end catch 

end 

私はあなたがここで解決しようとしている問題は、トリガなしで解決できるかどうかを検討するかもしれないのMS SQL 2016

+0

ここで希望する動作は何ですか?現在実装しているように、「他のデフォルトは0に設定されていますか」、または「empidごとに最大1つの行を1に設定できますか?後者の場合は、他のデータを変更する代わりにエラーを生成することもできますが、フィルタリングされたインデックスを使用して実装できます。 –

+0

@ damien-the-unbeliever:EmpIDごとに1つのレコード。私はテーブル内に複数のEmpIDを持つことができますが、1つだけにIsDefaultを設定することができます。他はすべて0でなければなりません。同じEmpIDのデフォルトアドレスを変更することは可能です。だから私は同じEmpIDのためにいくつかの他のアドレスでIsDefaultの値を変更できるようにするためにインデックスを使用することはできません。 – IvanVC

+0

「他の行を魔法のように変更する」動作をしたいのですか? (現在のデフォルト値を最初に設定解除してから新しいデフォルト値を設定すると、明らかにインデックスが正常に機能するため) –

答えて

1

私はマットに同意します:可能であれば、トリガーは避けてください。

とにかく、私はあなたのUPDATEトリガーであなたに変更すべきだと思う:あなたはあまりにもあなたの挿入トリガーを変更する必要があります

IF EXISTS(SELECT 1 FROM 
      FROM dbo.Addresses as lao 
      INNER join inserted as i on lao.EmpID = i.EmpID 
      WHERE lao.IsDefault = 1 AND lao.ID <>i.ID)   
      BEGIN 
       UPDATE lao 
       SET lao.IsDefault = 0 
       FROM dbo.Addresses as lao 
       INNER JOIN inserted as i on lao.EmpID = i.EmpID 
       WHERE lao.IsDefault = 1 
        and lao.ID <> i.id 
      END 

  if (
      select count(*) 
      from dbo.Addresses as lao 
      inner join inserted as i on lao.EmpID = i.EmpID 
      where lao.IsDefault = 1      
      ) > 1 
     begin 
      update lao 
      set lao.IsDefault = 0 
      from dbo.Addresses as lao 
      inner join inserted as i on lao.EmpID = i.EmpID 
      where lao.IsDefault = 1 
       and lao.ID <> i.id 
     end 

Morevore、あなたはそれを書き換えることができます。

更新:insert trigger。私は見ることができますが(テストはできませんので、完全なケーステストを行ってください)、IDが常に最大値である場合、または最後のIDのデフォルトを保持したい場合は、次のようにトリガー:(あなたも常にゼロ行のUPDATEをやって気にしない場合は、IFあまりにも削除することもできます)

as 
begin  
    set nocount on;  
    begin try 
     IF EXISTS(SELECT 1 
      FROM dbo.Addresses as lao 
      INNER join inserted as i on lao.EmpID = i.EmpID 
      WHERE lao.IsDefault = 1 
       AND lao.ID <>i.ID 
       AND i.IsDefault=1)   
      BEGIN 
       UPDATE lao 
       SET lao.IsDefault = 0 
       FROM dbo.Addresses as lao 
       INNER JOIN inserted as i on lao.EmpID = i.EmpID 
       WHERE lao.IsDefault = 1 
        and lao.ID <> i.id 
        AND i.IsDefault=1 
      END 
end try 
begin catch 
    if @@trancount > 0 
     rollback tran; 
end catch 

この変更は、(AND i.IsDefault = 1)は、トリガーを更新するためにも適用することができますあまりにも。

+0

私がマットに答えているように、他の方法でトリガーがあれば教えてください。私はトリガーにもなっていませんが、アップデートなしでフィールドの値を変更する必要がないため、トリガーを使用しないで行う方法を見つけることができません。 – IvanVC

+0

そして、私に言えば、私の挿入トリガーで何が間違っていますか?それとも、もし存在すればそれを書き直す方が良いということだけですか? – IvanVC

+1

あなたは挿入トリガーで "i.ID = lao.ID"を削除し、UPDATEトリガーのために書いたものと同じものを使うべきだと思っています(そしてCOUNTまたはEXISTSを使うことを選ぶことができます)。しかし、 。 – etsa

0

に取り組んでいます。トリガーはパフォーマンス上の不利益を被る傾向があり、残りのコードとロジックを分離することができ、将来的には維持するのが難しくなります。

行挿入/更新のトリガーソリューションを実際に使いたい場合は、常にその行に正確に1行しかマークされていないので、その行のカウントを計算しないでください。関連するEmpIDのすべての行を0に設定し、挿入された行をトリガーの後に1に更新するだけです。

+0

トリガーが他の方法であれば、私は聞くためにここにいる。私はそれがトリガなしではできないと考えていました。 – IvanVC

関連する問題