简体   繁体   English

SQL After Update触发器似乎阻止插入工作

[英]SQL After update trigger seems to prevent insert from working

I'm new to triggers and I can't seem to find an answer to this question. 我是触发器的新手,似乎找不到这个问题的答案。

I need to insert calculated rows in a table and have no access to the application source code. 我需要在表中插入计算出的行,并且无法访问应用程序源代码。 I thought a work around might be to create a trigger on the table to calculate the values based on the inserted values then insert them into the table, though I'm not real sure how this works. 我认为一种变通办法可能是在表上创建触发器以根据插入的值计算值,然后将其插入表中,尽管我不确定这是如何工作的。

I have the following trigger, it works for update, but doesn't work for insert. 我有以下触发器,它适用于更新,但不适用于插入。 If I remove "INSERT" in "FOR INSERT, UPDATE" it will insert the account_id field (which is the only non-null field), but not the rest. 如果我在“ FOR INSERT,UPDATE”中删除“ INSERT”,它将插入account_id字段(这是唯一的非空字段),而不是其余部分。 If I leave "INSERT" in, it will not insert any of the fields. 如果我将“ INSERT”保留在其中,则不会插入任何字段。

How can I make this work for both Inserts and updates? 如何使此功能适用于插入和更新?

ALTER TRIGGER [dbo].[SelfCalFieldsTrigger]
ON [dbo].[dynTable]
FOR INSERT, UPDATE
AS
BEGIN

Declare @acctID uniqueidentifier
Declare @invDiscPremPerc decimal(9,6)
Declare @investorSRP decimal(9,6)
Declare @purchWireAmt decimal(11,2)

set @acctID = (Select account_id from inserted) 

set @invDiscPremPerc = (Select Coalesce(INVESTOR_DISC_PREM_DOLLAR, 0)/
Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)*100 from inserted)


set @investorSRP = (Select Coalesce(INVESTOR_SRP_PREM_DOLLAR, 0)/
Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)*100 from inserted)


set @purchWireAmt = (Select Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)-
Coalesce(INVESTOR_ADMIN_FEE, 0)-
Coalesce(INVESTOR_WIRE_FEE, 0)- Coalesce(INVESTOR_FLOOD_FEE, 0)-
Coalesce(INVESTOR_TAX_SERVICE_FEE, 0) - Coalesce(INVESTOR_OTHER_FEE, 0) from     
inserted)


UPDATE [dbo].dynTable]
set INVESTOR_DISC_PREM_PERCENT = @invDiscPremPerc,
INVESTOR_SRP = @investorSRP,
PURCHASE_WIRE_AMOUNT = @purchWireAmt
Where [dbo].[dynTable].Account_ID = @acctID

END

You need to change the logic of your trigger. 您需要更改触发器的逻辑。 Right now, you are assuming that there is only one row inserted or updated, but that's not how it works. 现在,您假设仅插入或更新了一行,但这不是它的工作方式。 INSERTED is a pseudo table that contains all rows inserted or updated. INSERTED是一个伪表,其中包含所有插入或更新的行。 So, try this instead: 因此,请尝试以下操作:

ALTER TRIGGER [dbo].[SelfCalFieldsTrigger]
ON [dbo].[dynTable]
FOR INSERT, UPDATE
AS
BEGIN

    UPDATE A
    SET INVESTOR_DISC_PREM_PERCENT = ISNULL(B.INVESTOR_DISC_PREM_DOLLAR / 
                                            NULLIF(B.INVESTOR_PRIN_BAL_PURCHASED,0)*100,0),
    INVESTOR_SRP = ISNULL(B.INVESTOR_SRP_PREM_DOLLAR / 
                          NULLIF(B.INVESTOR_PRIN_BAL_PURCHASED,0)*100,0),
    PURCHASE_WIRE_AMOUNT =  COALESCE(B.INVESTOR_PRIN_BAL_PURCHASED, 0)-
                            COALESCE(B.INVESTOR_ADMIN_FEE, 0)-
                            COALESCE(B.INVESTOR_WIRE_FEE, 0)- 
                            COALESCE(B.INVESTOR_FLOOD_FEE, 0)-
                            COALESCE(B.INVESTOR_TAX_SERVICE_FEE, 0)- 
                            COALESCE(B.INVESTOR_OTHER_FEE, 0)
    FROM [dbo].[dynTable] A
    INNER JOIN INSERTED B
        ON A.Account_ID = B.Account_ID

END

I agree with the above comment. 我同意以上评论。 The inserted table can have 1 to n rows. 插入的表可以有1到n行。

I have two other suggestions other than a trigger. 除了触发器之外,我还有另外两个建议。

You can create a function to wrap up the business logic in a neat package. 您可以创建一个函数来将业务逻辑包装在一个简洁的程序包中。

1 - Can you change the table design and add a persisted computed column ? 1-您可以更改表设计并添加持久化的计算列吗?

Use the above function in the design. 在设计中使用以上功能。

2 - How about creating a view with the calculated field in the SELECT statement? 2-如何在SELECT语句中使用计算字段创建视图

Use the above function in the design. 在设计中使用以上功能。

Last but not least, a trigger solution that works for both null and zero values. 最后但并非最不重要的一点是,适用于空值和零值的触发器解决方案。

--
-- Sample table
--

-- Use temp database
USE TEMPDB;
GO

-- Remove old object
IF OBJECT_ID('DBO.INVESTOR') > 1
    DROP TABLE DBO.INVESTOR
GO

-- Create new object
CREATE TABLE DBO.INVESTOR
(
    INVESTOR_ID INT IDENTITY(1, 1),
    INVESTOR_PRIN_BAL_PURCHASED MONEY,
    INVESTOR_DISC_PREM_DOLLAR MONEY,
    INVESTOR_SRP_PREM_DOLLAR MONEY,
    INVESTOR_ADMIN_FEE MONEY,
    INVESTOR_WIRE_FEE MONEY,
    INVESTOR_FLOOD_FEE MONEY,
    INVESTOR_TAX_SERVICE_FEE MONEY,
    INVESTOR_OTHER_FEE MONEY,
    INVESTOR_DISC_PREM_PERCENT REAL,
    INVESTOR_SRP REAL,
    PURCHASE_WIRE_AMOUNT MONEY
);


--
-- Sample trigger
--

-- Remove old object
IF OBJECT_ID('DBO.CALCULATE_FEILDS') > 1
    DROP TRIGGER DBO.CALCULATE_FEILDS
GO

-- Create new object
CREATE TRIGGER DBO.CALCULATE_FEILDS ON DBO.INVESTOR
FOR INSERT, UPDATE AS
BEGIN

    UPDATE 
        DBO.INVESTOR
    SET 
        INVESTOR_DISC_PREM_PERCENT = 
            CASE WHEN INVESTOR_PRIN_BAL_PURCHASED <> 0 THEN
                Coalesce(INVESTOR_DISC_PREM_DOLLAR, 0) /
                Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0) * 100
            ELSE 0 END,

        INVESTOR_SRP = 
            CASE WHEN INVESTOR_PRIN_BAL_PURCHASED <> 0 THEN
                Coalesce(INVESTOR_SRP_PREM_DOLLAR, 0) /
                Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0) * 100
            ELSE 0 END,
        PURCHASE_WIRE_AMOUNT = 
            Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0) -
            Coalesce(INVESTOR_ADMIN_FEE, 0) -
            Coalesce(INVESTOR_WIRE_FEE, 0) - 
            Coalesce(INVESTOR_FLOOD_FEE, 0) -
            Coalesce(INVESTOR_TAX_SERVICE_FEE, 0) - 
            Coalesce(INVESTOR_OTHER_FEE, 0)
    WHERE 
        INVESTOR_ID IN (Select i.INVESTOR_ID From inserted i)

END
GO

--
-- Sample data (zeros & nulls)
--

INSERT INTO DBO.INVESTOR
(
    INVESTOR_PRIN_BAL_PURCHASED,
    INVESTOR_DISC_PREM_DOLLAR,
    INVESTOR_SRP_PREM_DOLLAR,
    INVESTOR_ADMIN_FEE,
    INVESTOR_WIRE_FEE,
    INVESTOR_FLOOD_FEE,
    INVESTOR_TAX_SERVICE_FEE,
    INVESTOR_OTHER_FEE
) 
VALUES 
(0, 0, 0, 0, 0, 0, 0, 0),
(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);

-- Show the data
SELECT * FROM TEMPDB.DBO.INVESTOR

Try it like this, it should fix both problems: 尝试这样,它可以解决两个问题:

ALTER TRIGGER [dbo].[SelfCalFieldsTrigger] ON [dbo].[dynTable]
FOR INSERT, UPDATE AS
BEGIN

    UPDATE [dbo].dynTable
        SET INVESTOR_DISC_PREM_PERCENT = Coalesce(INVESTOR_DISC_PREM_DOLLAR, 0)/
                Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)*100,
            INVESTOR_SRP = Coalesce(INVESTOR_SRP_PREM_DOLLAR, 0)/
                Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)*100,
            PURCHASE_WIRE_AMOUNT = Coalesce(INVESTOR_PRIN_BAL_PURCHASED, 0)-
                Coalesce(INVESTOR_ADMIN_FEE, 0)-
                Coalesce(INVESTOR_WIRE_FEE, 0)- Coalesce(INVESTOR_FLOOD_FEE, 0)-
                Coalesce(INVESTOR_TAX_SERVICE_FEE, 0) - Coalesce(INVESTOR_OTHER_FEE, 0)
    WHERE Account_id IN(Select i.Account_id From inserted i)

END

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM