2009-06-19 3 views
1

내가 다른 테이블에 데이터를 다시 삽입 할 필요가있는 트리거에서 일하고 있어요 삽입 TSQL에 트리거합니다.가 아닌 정체성 테이블

대상 테이블은 정체성없이 NOT NULL 기본 키의 INT를 가지고, 그래서 나는이 개 선택이 있습니다

  1. 최대를 계산하고 여기에서 삽입을.
  2. 시퀀스 테이블에서 최대 값을 가져옵니다.

항상 ID로 테이블 변수를 만들고 이전에 계산 된 값에서 삽입하는 데 사용합니다.

CREATE TRIGGER trg 
    ON [dbo].[table] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @t TABLE (sec INT IDENTITY(1, 1), id INT) 
    DECLARE @ini INT 

    SELECT @ini = ISNULL(MAX(id), 0) FROM tableDest 
    -- SELECT @ini = value FROM sequencesTable WHERE seqId = 987 

    INSERT INTO @t (id) SELECT id FROM inserted 

    INSERT INTO tableDest 
     (id, field1, field2) 
    SELECT @ini + t.sec, field1, field2 
    FROM @t t 
     JOIN inserted ON t.id = inserted.id 


    -- SELECT @ini = @ini + MAX(t.sec) FROM @t 
    -- UPDATE sequencesTable SET value = @ini WHERE seqId = 987 
END 

더 좋은 방법이 있나요?

미리 감사드립니다.

+0

다른 테이블에있는 int PK의 의도와 의미가 무엇인지 결정해야합니다. 이것이 올바른 키 값을 제공 할 수있는 유일한 방법입니다. – RBarryYoung

답변

2

, 당신은 ROW_NUMBER()를 사용할 수 있습니다

CREATE TRIGGER trg 
    ON [dbo].[table] 
    AFTER INSERT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    INSERT INTO tableDest 
     (id, field1, field2) 
    SELECT 
     Seed.Value + ROW_NUMBER() OVER(ORDER BY Id), 
     field1, 
     field2 
    FROM Inserted 
    CROSS JOIN (
     SELECT MAX(id) as Value 
     FROM tableDest 
    ) as Seed 
END 

CROSS JOIN을하는 대신 시드 값은 값을 직접 받고를 삽입 사이에 변화 MAX(Id)의 동시성 두통에서 당신을 저장지고. 그렇지 않으면 읽은 후에 새 행이 tableDest에 삽입되지 않도록하려면 SERIALIZABLE 트랜잭션이 필요합니다.

+0

불행히도 sql2000 –

+0

계속 시드 값에 대해 CROSS JOIN을 수행하지만 증분 값을 얻으려면 테이블 변수를 사용해야합니다. –

0

합니까 tableDest 정말 인공 기본 키를해야합니까? 또한

, 동시성 : 당신이 @ini의 값을 계산하고 실제로 삽입을하는 사이에 tableDest에서 일어나는 다른 삽입의 가능성이있다? SQL 2005 + 가정

+0

Well 나는 BEGIN TRAN/COMMIT을 둘러싸는 것으로 동시성 문제를 해결할 생각을했습니다. –

+0

tran/commit을 사용하여 트리거 내에서 코드를 래핑하면 아무 것도 사지 않을 것입니다. 트리거는 암시 적 트랜잭션입니다. –

+0

CTE가 개선 될 수 있습니까? 비슷해 WITH INI (오프셋) AS tableDest INSERT INTO tableDest (ID, 필드 1, 2 필드) SELECT ini.offset + inserted.sec, inserted.field1, inserted.field2 오프셋 SELECT MAX (ID) AS INI CROSS JOIN에서 삽입했습니다. CTE가 원자 적으로 보장되는지 확실하지 않습니다. 본래의 질문은 여전히 ​​남아 있습니다. 고유 한 ID 열이 정말로 필요한가요? 아니면 "모든 테이블에 ID 필드가 있어야합니다"규칙을 제공해야합니까? –

0

는 내가 대상 테이블에 ID 값을 설정하지 왜 뻔한 질문을 요청할 것 같아요? (주의 할 점은 소스 테이블에서 ID 값을 얻기 위해 @@ ID를 사용하지 않는다는 것입니다. 목적지 테이블에서 ID를 얻습니다.)

아니면 다른 테이블의 ID와 소스 테이블에서 신원을 사용할 수 있습니다. 그것은 디자인의 원래 의도로 나를 공격합니다. 그렇지 않으면 이러한 레코드를 원본 데이터와 일치시키는 것이 어려울 수 있습니다.

1

그냥 내가이 문을 실행하면 동시에 많은 문이 병렬로 한 번에 실행된다하더라도, 그것은 항상 나에게 표 푸에 고유 한 바를 제공합니다 명확히?

INSERT INTO Foo (Bar) 
    SELECT 
    CASE WHEN Bar = -1 
    THEN (SELECT Seed.Value + ROW_NUMBER() OVER(ORDER BY AutoId) 
      FROM inserted CROSS JOIN (SELECT MAX(Bar) as Value FROM Foo) as Seed) 
    ELSE Bar 
    END 

이 경우 명령문의 동시성을 안전하게하는 것은 무엇입니까? Bar의 새 값을 생성하는 select가 insert 문에 중첩되어 있기 때문입니까? 또는 테이블 Foo에 대한 동시 읽기 액세스를 방지하는 크로스 조인입니까? case 문은 어떻습니까? 동시성과 관련하여 결과에 영향을 미칩니 까?

감사합니다.

관련 문제