한 테이블에서 다른 테이블로 행 이동


9

보관 프로세스의 일환으로 한 데이터베이스에서 다른 데이터베이스로 레코드를 이동하고 있습니다. 행을 대상 테이블에 복사 한 다음 소스 테이블에서 동일한 행을 삭제하려고합니다.

내 질문은 행을 삭제하기 전에 첫 번째 삽입이 성공했는지 확인하는 가장 효율적인 방법은 무엇입니까?

내 생각은 이것이지만 더 좋은 방법이 있다고 생각합니다.

@num_records=select count(ID) from Source_Table where (criteria for eligible rows)

insert * into Destination_Table where (criteria for eligible rows)

if ((select count(ID) from Destination_Table where (criteria) )=@numrecords)

delete * from Source_Table where (criteria)

RAISERROR 기능과 결합하는 것이 더 좋거나 가능합니까? 감사합니다!

답변:


13

명시 적 트랜잭션과 함께 TRY / CATCH 구문을 권장 합니다. 이 솔루션에 대한 내 가정은 삽입 실패의 원인이 일종의 트랩 가능한 SQL 오류 (예 : 키 위반, 데이터 유형 불일치 / 변환 오류 등)이기 때문입니다. 구조는 다음과 같습니다.

BEGIN TRAN

BEGIN TRY
  INSERT INTO foo(col_a,col_b,col_c,recdate)
  SELECT col_a,col_b,col_c,recdate
  FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  DELETE FROM bar
  WHERE recdate BETWEEN @startdate AND @enddate

  COMMIT TRAN
END TRY
BEGIN CATCH
  ROLLBACK TRAN
END CATCH

INSERT 또는 DELETE에서 오류가 발생하면이 구조가 작동하는 방식으로 전체 조치가 롤백됩니다. 이를 통해 전체 조치가 완료되어야합니다. 필요하다고 느꼈다면 2012 년의 THROW 또는 2008 년 및 이전의 RAISERROR 와 결합하여 로직을 추가하고 해당 로직이 충족되지 않으면 롤백을 강제 실행할 수 있습니다.

또 다른 옵션은 SET XACT_ABORT ON 을 보는 것입니다.하지만 TRY / CATCH 구문이 더 세분화됩니다.


19

보관 테이블에 없는 경우 .

  • 트리거를 정의했습니다.
  • FOREIGN KEY 제약 조건의 양쪽에 참여하십시오.
  • CHECK 제약 조건 또는 활성화 된 규칙이 있어야합니다.

한 상태에서 할 수도 있습니다.

DELETE FROM source_table
OUTPUT deleted.Foo,
       deleted.Bar,
       SYSUTCDATETIME()
INTO archive_table(Foo, Bar, archived)
WHERE  Foo = 1; 

이 중 하나를 성공하거나 하나의 단위로 실패하고 또한 행 사이에 추가되는 가능한 경쟁 조건을 방지 할 INSERT아카이브와 DELETE(당신하지만 WHERE절 잘이 매우 가능성이 어쨌든을 할 수 있습니다).


위의 어느 것도 아닙니다. 나는 그 길을 갈 수 있다고 생각한다. 나는 코드 미니멀리즘을 좋아한다. 삽입이 어떤 이유로 든 실패하면 레코드를 잃고 싶지 않습니다. (예 : 테이블 잠금, 시간 초과 등) 감사합니다!
Dina

@ 디나-당신은 OUTPUT절에서 가능하다는 것을 나타 냈습니까 ? 그것은 모두 하나의 진술이기 때문이 아닙니다. 또한 행을 두 번 읽어야하는 문제 (및 삽입에 대한 읽기와 삭제에 대한 읽기 사이에 추가 된 행이 손실 될 수 있음)를 피하십시오.
Martin Smith

그렇습니다. 고마워요, 당신의 요점을 참조하십시오.
Dina

FWIW-이 방법을 사용하면 로그 파일이 원래 테이블 크기에 가깝게 커집니다. 그걸로 살 수 있는지 확인하십시오. 그렇지 않으면 DELETE TOP (N)과 @@ rowcount 변수를 확인하는 While 루프를 사용하여 배치로 나눕니다.
Wjdavis5

1

아카이빙에 대해 생각한 방법은 (아무도 완벽하지는 않습니다) 레코드를 성공적으로 전송 한 후 1의 값을 갖는 '아카이브'와 같은 새 아카이브 테이블에 비트 열을 추가하는 것입니다. 모든 레코드를 전송 한 후에는 아카이브 된 테이블에서이 '아카이브 된'필드 값 '1', 즉 True를 찾는 동안 삭제 조작을 수행 할 수 있습니다.

그리고 Try / Catch 사용에 대해 Mike에게 동의합니다.


1

이 시도:

INSERT dbo.newtable(
      name,
      department,
      Salary
) SELECT 
            name,
            FirstName,
            Lastname
      FROM    (
           DELETE dbo.oldtable
           OUTPUT
                   DELETED.name,
                   DELETED.department,
                   DELETED.Salary
           WHERE ID  IN ( 1001, 1003, 1005 )
      ) AS RowsToMove;

SELECT * FROM dbo.newtable;
SELECT * FROM dbo.oldtable;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.