문제

나는 이 일을 행하기 전에 어딘가에 나가 확실하다.

나는 SQL Server2000 테이블을 필요로 로그를 변경하는 필드에 삽입 업데이트 및으로 두 번째 로깅이다.간단한 버전을의 구조는 내용은 다음과 같습니다.

MainTable
ID varchar(10) PRIMARY KEY
DESCRIPTION varchar(50)

LogTable
OLDID varchar(10)
NEWID varchar(10)

다른 분야가 이와 같은 작동:

Select i.DESCRIPTION As New, d.DESCRIPTION As Old 
From Inserted i
LEFT JOIN Deleted d On i.ID=d.ID

...하지만 분명히 가입하세이 실패하는 경우 ID 를 변경되었습니다.

나는 수정할 수 없습니다 테이블에서 방법으로,이만 힘이 나는 이 데이터베이스를 만드는 것입니다.

또는 있는 사람을 가르칠 수 있는 나에게 여행하는 시간 및 다운로드가 가능합니다.으로 자신에게 그때 나는 어떻게 이런 짓을 했죠?환호:)


편집:

나는 생각을 명확히 할 필요가 몇 일들이 여기에 있습니다.이 실제로 나는 데이터베이스,그것은 기존 시스템 내가 거의 없음의 제어,다른 것보다 이것을 쓰고 있다.

나의 질문은 어떻게 검색 할 수 있습니다 오래된 기본 키가 있는 경우 말했 기본 키가 변경되었습니다.내가 필요로 하지 않는 말을하지 않았어 변경 또는 기본 키에 대해 쫓는 외국습니다.는 내 문제가:)

도움이 되었습니까?

해결책

트리거에 제시된 삽입 및 삭제 된 테이블이 동일한 순서로 보장된다고 가정 할 수 있습니까?

다른 팁

DECLARE @OldKey int, @NewKey int;

SELECT @Oldkey = [ID] FROM DELETED;
SELECT @NewKey = [ID] FROM INSERTED;

이것은 단일 행이있는 경우에만 작동합니다. 그렇지 않으면 오래된 행과 새 행을 연결할 "앵커"가 없습니다. 따라서 삽입 된> 1에 대한 트리거를 확인하십시오.

나는 그것이 가능하지 않다고 생각합니다. 테이블에 4 개의 행이 있다고 상상해보십시오.

1  Val1
2  Val2
3  Val3
4  Val4

이제 다음 업데이트를 발행합니다.

UPDATE MainTable SET
ID = CASE ID WHEN 1 THEN 2 WHEN 2 THEN 1 ELSE ID END
Description = CASE ID WHEN 3 THEN 'Val4' WHEN 4 THEN 'Val3' ELSE Description END

이제, 당신은 어떻게 행 1 & 2 행에서 일어난 일과 3 행 4에서 일어난 일을 어떻게 구별 할 것인가? 그리고 더 중요한 것은 그들 사이의 다른 점을 설명 할 수 있습니까? 어떤 열이 업데이트되었는지 알려주는 모든 것들이 도움이되지 않습니다.

이 경우 테이블에 추가 키가있을 수 있다면 (예 : 설명은 고유합니다) 업데이트 규칙이 허용되면 트리거를 작성하여 두 키에 대한 동시 업데이트를 방지 할 수 있습니다. 두 테이블을 상관시키기 위해 업데이트되었습니다.

다중 줄 인서트/업데이트를 처리해야하고 변경하지 않아야 할 대체 키가 없으면이 작업을 수행 할 수있는 유일한 방법은 트리거 대신 사용하는 것입니다. 예를 들어 트리거에서 원래 삽입/업데이트 명령을 행당 하나의 명령으로 나누고 삽입/업데이트 전에 각각의 ID를 잡을 수 있습니다.

SQL Server의 트리거 내에서 삭제 및 삽입 된 두 개의 테이블에 액세스 할 수 있습니다. 이 두 가지 모두 이미 언급되었습니다. 트리거가 발사되는 조치에 따라 다음과 같은 기능은 다음과 같습니다.

작동을 삽입하십시오

  • 삭제 - 사용되지 않습니다
  • 삽입 - 테이블에 추가되는 새 행이 포함되어 있습니다.

작업 삭제

  • 삭제 - 테이블에서 제거되는 행이 포함되어 있습니다.
  • 삽입 - 사용되지 않습니다

업데이트 작업

  • 삭제 - 업데이트 작업 전에 존재하는 행을 포함합니다.
  • 삽입 - 업데이트 작업 후 존재하는 행이 포함되어 있습니다.

테이블과 같은 모든 방식으로 이러한 기능. 따라서 다음과 같은 것과 같은 행 기반 작업을 전적으로 사용하는 것이 가능합니다 (작업 테이블에만 운영이 존재합니다. DateChanged와 같이).

INSERT INTO MyAuditTable
(ID, FirstColumn, SecondColumn, ThirdColumn, Operation, DateChanged)
VALUES
SELECT ID, FirstColumn, SecondColumn, ThirdColumn, 'Update-Before', GETDATE()
FROM deleted
UNION ALL
SELECT ID, FirstColumn, SecondColumn, ThirdColumn, 'Update-After', GETDATE()
FROM inserted

---- 새 ---- 응용 프로그램이 변경 될 수없는 테이블에 ID 열을 추가 한 다음 해당 새 열을 사용하여 트리거 내의 삭제 된 테이블에 삽입 된 삽입 된 테이블에 가입 할 수 있습니다.

ALTER TABLE YourTableName ADD
    PrivateID int NOT NULL IDENTITY (1, 1)
GO

---- Old ---- 키 값을 업데이트/변경하지 마십시오. 어떻게 이렇게하고 모든 외국 열쇠를 수정할 수 있습니까?

행을 처리 할 수없는 트리거를 사용하지 않는 것이 좋습니다.

키를 변경 해야하는 경우 적절한 새 키와 값으로 새 행을 삽입하면 Scope_Identity ()를 사용하는 경우 사용하는 경우 사용하십시오. 이전 행을 삭제하십시오. 오래된 행을 로그인 새 행의 키로 변경되었는데, 이제 가야합니다. 로그에 변경된 키에 외국 키가 없기를 바랍니다 ...

테이블 maintable (예 : CorrelationId와 같은 이름)에 새 ID 열을 만들 수 있으며이 열을 사용하여 삽입 및 삭제 된 테이블을 상관시킬 수 있습니다. 이 새 열은 기존 코드의 경우 투명해야합니다.

INSERT INTO LOG(OLDID, NEWID)
SELECT deleted.id AS OLDID, inserted.id AS NEWID
FROM inserted 
INNER JOIN deleted 
    ON inserted.correlationid = deleted.correlationid

주의를 기울이면 로그 테이블에 중복 레코드를 삽입 할 수 있습니다.

물론 아무도해야 합 변화하는 기본 키 테이블에 하나는 정확하게 트리거가 있어야에 대한(부분),은 사람들을 유지하는 일을 하기에서 그들이 하면 안되는 행동을 했어요.그것은 간단한 작업에서 Oracle MySQL 쓰 트리거을 가로채는 변경을 기본 키고 그들을 중지하지만,모든 SQL Server.

당신의 사랑을 할 수 있는 것이 단순히 다음과 같은 것이 가능합니다.

if exists
  (
  select *
    from inserted changed
           join deleted old
   where changed.rowID = old.rowID
     and changed.id != old.id
  )
... [roll it all back]

는 이유는 사람들이 밖으로 나가서 인터넷 검색에 대한 SQL 서버의 동 ROWID.론,SQL 서버는 그것이 없습니다;그래서 당신은 다른 접근 방식이다.

빠른하지만,슬프게도지 않는 방탄,버전을 쓰는 대신 업데이트의 트리거를 보이는지 여부를 확인 어떤 행 삽입 기본 키가 있에서 발견되지 않 업데이트된 테이블 또는 그 반대입니다.이를 잡을 것이 전부는 아니지만 대부분의 오류:

if exists
  (
  select *
    from inserted lost
           left join updated match
             on match.id = lost.id
   where match.id is null
  union
  select *
    from deleted new
           left join inserted match
             on match.id = new.id
    where match.id is null
  )
  -- roll it all back

그러나 이것은 여전히지 않는 catch 업데이트처럼...

update myTable
   set id = case
              when id = 1 then 2 
              when id = 2 then 1
              else id
              end

나는 지금도 가정을 만드는 삽입과 삭제한 테이블에서 주문하는 그런 방법으로 cursoring 를 삽입과 삭제는 테이블 동시에 당신을 줄 것이 제대로 일치하는 행이 있습니다.이 나타납니다.효과에서 당신이 설정 트리거로 동의한 각 행 트리거를 사용할 수 있습에서 오라클 및 필수에서 MySQL...그러나 나는 상상 성능이 나쁜 것입에 대규모 업데이트 않기 때문에 이 기본 동작하는 SQL Server.또한 그에 따라 달라집 가정할 수 없는 실제로 찾기 문서화 어디서나 그래서 꺼려에 따라 달라집니다.하지만 코드를 구성하는 방법으로 나타나 제대로 작동하려면에 내 SQL Server2008R2 설치합니다.스크립트 끝에서 이 게시물의 하이라이트 모두의 동작이 빠르지 않음-방탄 솔루션과 동작의 두 번째,의사 Oracle 솔루션입니다.

면 누구나 다 할 수 있다는 점을 곳으로는 나의 가정은 문서화하고 보장하여 Microsoft 내가 매우 감사 사람이...

begin try
  drop table kpTest;
end try
begin catch
end catch
go

create table kpTest( id int primary key, name nvarchar(10) )
go

begin try
  drop trigger kpTest_ioU;
end try
begin catch
end catch
go

create trigger kpTest_ioU on kpTest
instead of update
as
begin
  if exists
    (
    select *
      from inserted lost
             left join deleted match
               on match.id = lost.id
     where match.id is null
    union
    select *
      from deleted new
             left join inserted match
               on match.id = new.id
      where match.id is null
    )
      raisError( 'Changed primary key', 16, 1 )
  else
    update kpTest
       set name = i.name
      from kpTest
             join inserted i
               on i.id = kpTest.id
    ;
end
go

insert into kpTest( id, name ) values( 0, 'zero' );
insert into kpTest( id, name ) values( 1, 'one' );
insert into kpTest( id, name ) values( 2, 'two' );
insert into kpTest( id, name ) values( 3, 'three' );

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/

-- This throws an error, appropriately
update kpTest set id = 5, name = 'FIVE' where id = 1
go

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/

-- This allows the change, inappropriately
update kpTest 
   set id = case   
              when id = 1 then 2
              when id = 2 then 1
              else id
              end
     , name = UPPER( name )
go

select * from kpTest

/*
0   ZERO
1   TWO   -- WRONG WRONG WRONG
2   ONE   -- WRONG WRONG WRONG
3   THREE
*/

-- Put it back
update kpTest 
   set id = case   
              when id = 1 then 2
              when id = 2 then 1
              else id
              end
     , name = LOWER( name )
go

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/

drop trigger kpTest_ioU
go

create trigger kpTest_ioU on kpTest
instead of update
as
begin
  declare newIDs cursor for select id, name from inserted;
  declare oldIDs cursor for select id from deleted;
  declare @thisOldID int;
  declare @thisNewID int;
  declare @thisNewName nvarchar(10);
  declare @errorFound int;
  set @errorFound = 0;
  open newIDs;
  open oldIDs;
  fetch newIDs into @thisNewID, @thisNewName;
  fetch oldIDs into @thisOldID;
  while @@FETCH_STATUS = 0 and @errorFound = 0
    begin
      if @thisNewID != @thisOldID
        begin
          set @errorFound = 1;
          close newIDs;
          deallocate newIDs;
          close oldIDs;
          deallocate oldIDs;
          raisError( 'Primary key changed', 16, 1 );
        end
      else
        begin
          update kpTest
             set name = @thisNewName
           where id = @thisNewID
          ;
          fetch newIDs into @thisNewID, @thisNewName;
          fetch oldIDs into @thisOldID;
        end
    end;
  if @errorFound = 0
    begin
      close newIDs;
      deallocate newIDs;
      close oldIDs;
      deallocate oldIDs;
    end
end
go

-- Succeeds, appropriately
update kpTest
   set name = UPPER( name )
go

select * from kpTest;

/*
0   ZERO
1   ONE
2   TWO
3   THREE
*/

-- Succeeds, appropriately
update kpTest
   set name = LOWER( name )
go

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/


-- Fails, appropriately
update kpTest 
   set id = case   
              when id = 1 then 2
              when id = 2 then 1
              else id
              end
go

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/

-- Fails, appropriately
update kpTest 
   set id = id + 1
go

select * from kpTest;

/*
0   zero
1   one
2   two
3   three
*/

-- Succeeds, appropriately
update kpTest 
   set id = id, name = UPPER( name )
go

select * from kpTest;

/*
0   ZERO
1   ONE
2   TWO
3   THREE
*/

drop table kpTest
go
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top