2010-11-29 7 views
1

올바르게 작동하기 위해 TSQL 트리거를 가져 오는 데 문제가 있습니다. 난 디버거를 통해 그것을 실행했습니다 및 모든 SQL Server Management Studio에 따라 변수를 설정하지 않습니다. 가장 당연한 일은 트리거 자체가 올바르게 실행되고 실행될 때 오류가 없다는 것입니다 ('실행 성공'이라고 말함).TSQL 트리거가 변수를 저장하지 못하거나 제대로 실행되지 않음

USE TestDb 

IF EXISTS (SELECT name FROM sysobjects 
     WHERE name = 'OfficeSalesQuotaUpdate' AND type = 'TR') 
    DROP TRIGGER OfficeSalesQuotaUpdate 
GO 

CREATE TRIGGER OfficeSalesQuotaUpdate 
ON SalesReps 
AFTER UPDATE, DELETE, INSERT 
AS 
    DECLARE @sales_difference int, @quota_difference int 
    DECLARE @sales_original int, @quota_original int 
    DECLARE @sales_new int,   @quota_new int 

    DECLARE @officeid int 
    DECLARE @salesrepid int 

    --UPDATE(Sales) returns true for INSERT and UPDATE. 
    --Not for DELETE though.  

    IF ((SELECT COUNT(*) FROM inserted) = 0) 
     SET @salesrepid = (SELECT SalesRep FROM deleted) 
    ELSE  
     SET @salesrepid = (SELECT SalesRep FROM inserted) 

    --If you address the @salesrepid variable, it does not work. Doesn't even 
    --print out the 'this should work line. 
    PRINT 'This should work...' --+ convert(char(30), @salesrepid) 

    IF (@salesrepid = NULL) 
     PRINT 'SalesRepId is null' 
    ELSE 
     PRINT 'SalesRepId is not null' 

    PRINT convert(char(50), @salesrepid) 


    SET @officeid = (SELECT RepOffice 
         FROM SalesReps 
         WHERE SalesRep = @salesrepid) 

    SELECT @sales_original = (SELECT Sales FROM deleted) 
    SELECT @sales_new =   (SELECT Sales FROM inserted) 

    --Sales can not be null, so we'll remove this later. 
    --Use this as a template for quota though, since that can be null. 
    IF (@sales_new = null) 
    BEGIN 
     SET @sales_new = 0 
    END 

    IF (@sales_original = 0) 
    BEGIN 
     SET @sales_original = 0 
    END 

    SET @sales_difference = @sales_new - @sales_original 

    UPDATE Offices 
    SET Sales = Sales + @sales_difference 
    WHERE Offices.Office = @officeid 
GO 

을 그래서, 어떤 조언 : (그냥 익숙한 내 자신을 점점 .... 진행중인 작품이다)은 다음과 같이

코드는 무엇입니까? 나는 이걸 완전히 뒤엎았다. 미리 감사드립니다.

+2

다른 무엇이든 잘못 여기 수 있습니다 (원본이 아니라 상정하지, 중 올바른 얻을) 다중 행 조작에 잘 대처하기 위해 쓰여졌습니다 - 삽입 및 삭제 된 의사 테이블은 여러 행을 포함 할 수 있습니다. –

+0

괜찮습니다. 단지 수업 시간입니다. 그러나 다른 한편으로, 둘 이상의 행이있을 때 가상 '삽입 된'테이블과 '업데이트 된'테이블 각각에서 두 행을 갖는 방법을 어떻게 알 수 있습니까? – Nitrodist

답변

2

귀하의 주요 문제가 @foo = NULL@foo IS NULL 사이에 차이가 있음을 것 같다 :

declare @i int 
set @i = null -- redundant, but explicit 

if @i = null print 'equals' 
if @i is null print 'is' 

다음은 문자열이있는 NULL을 연결하는 것은 NULL을 제공하기 때문에 작동하지 않습니다 PRINT 문 '이 작동합니다' PRINT NULL은 아무 것도 인쇄하지 않습니다.

실제로 @salerepid의 값을 설정하는 경우 삽입되거나 삭제 된 테이블이 실제로 비어있는 것 같습니다. 방아쇠를 테스트하기 위해 어떤 진술을 사용하고 있습니까? 그리고 COUNT (*) 값을 출력 했습니까?

누군가가 한 번에 두 개 이상의 행을 변경하면 어떻게 될지 고려해야합니다. 현재 코드에서는 한 번에 하나의 행만 변경된다고 가정합니다. 이는 사용자 환경에서 적절한 가정 일 수 있지만, 누군가 데이터를 대량로드하거나 다른 '일괄 처리'를 수행하면 쉽게 손상 될 수 있습니다.

마지막으로 항상 MSSQL 버전과 에디션을 언급해야합니다. 일부 구문 문항과 관련 될 수 있습니다.

0

그냥 제안 ... 트리거의 '부분'을 캡슐화하기 위해 BEGIN 및 END를 넣으려고 했습니까?

+0

'TRIGGER'는'TRIGGER'의 끝을 의미하기 때문에'GO'가 필요하지 않습니다. – Nitrodist

2

이 같은과 트리거의 몸을 교체해야합니다 :이 적절하게 삽입 및 삭제에 여러 행에 대응합니다

;WITH Totals AS (
    SELECT RepOffice,SUM(Sales) as Sales FROM inserted GROUP BY RepOffice 
    UNION ALL 
    SELECT RepOffice,-SUM(Sales) FROM deleted GROUP BY RepOffice 
), SalesDelta AS (
    SELECT RepOffice,SUM(Sales) as Delta FROM Totals GROUP BY RepOffice 
) 
UPDATE o 
SET Sales = Sales + sd.Delta 
FROM 
    Offices o 
     inner join 
    SalesDelta sd 
     on 
      o.Office = sd.RepOffice 

. SalesRep이 SalesReps 테이블의 기본 키라고 가정합니다.


특정 영업 담당자의 RepOffice 변화 UPDATE에 대처하기 위해, 위의 업데이트 '트리거의 ISN,

+0

어디에서 델타가 선택됩니까? – Nitrodist

+0

@Nitrodist - 업데이트 문 앞에 CTE에 새로 추가 된 열입니다. 삽입 된 테이블 (특정 RepOffice의 경우)에서 삭제 된 테이블의 모든 판매 값의 합계를 뺀 값입니다 (for 동일한 RepOffice) –

+0

그래서 'FROM Totals'가되어서는 안됩니까? 그 성명서에? – Nitrodist

관련 문제