Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
walank
Starting Member
12 Posts |
Posted - 2009-07-04 : 12:07:59
|
3 tables: invoice, payment, posting (create query on the bottom)I need triggers with following functionality:- disallow insert/update in posting table if sum(posted Amount) > Invoice total. (partially done)- disallow insert/update in posting table if sum(Posted Amount) > Payment amount.- disallow delete in Invoice/payment table if record exist in posting (DONE)I already wrote 2 triggers which are working if 1 record inserted/updated - I need it for many records...Thanks in advance !Here is create statement:USE [simpleAccounting]GO/****** Object: Table [dbo].[invoice] Script Date: 07/04/2009 10:47:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[invoice]( [InvoiceID] [int] IDENTITY(1,1) NOT NULL, [Amount] [money] NOT NULL CONSTRAINT [DF_invoice_Amount] DEFAULT ((0.00)), CONSTRAINT [PK_invoice] PRIMARY KEY CLUSTERED ( [InvoiceID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO/****** Object: Table [dbo].[payment] Script Date: 07/04/2009 10:47:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[payment]( [paymentID] [int] IDENTITY(1,1) NOT NULL, [amount] [money] NOT NULL CONSTRAINT [DF_payment_amount] DEFAULT ((0.00)), CONSTRAINT [PK_payment] PRIMARY KEY CLUSTERED ( [paymentID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO/****** Object: Table [dbo].[posting] Script Date: 07/04/2009 10:47:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TABLE [dbo].[posting]( [postingID] [int] IDENTITY(1,1) NOT NULL, [invoiceID] [int] NULL, [paymentID] [int] NULL, [amount] [money] NULL, CONSTRAINT [PK_posting] PRIMARY KEY CLUSTERED ( [postingID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO/****** Object: Trigger [check_totals_update] Script Date: 07/04/2009 10:47:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE TRIGGER [dbo].[check_totals_update] ON [dbo].[posting] after UPDATEAS DECLARE @lc_insert_amount as char(20)DECLARE @lc_delete_amount as char(20)DECLARE @lc_sum_posted as char(20)DECLARE @lc_invoice_total as char(20)DECLARE @lc_message as char(254)BEGINIF EXISTS(SELECT 1 FROM inserted i WHERE ((SELECT SUM(posting.amount) FROM posting posting WHERE posting.invoiceID=i.InvoiceID)> (SELECT Invoice.Amount FROM Invoice Invoice WHERE invoice.InvoiceID=i.InvoiceID)) ) BEGIN select @lc_insert_amount=CAST(amount as varchar(20)) from inserted select @lc_delete_amount=CAST(amount as varchar(20)) from deleted select @lc_sum_posted=CAST(SUM(posting.amount) as varchar(20)) FROM inserted i RIGHT OUTER JOIN posting posting ON posting.invoiceID=i.InvoiceID select @lc_invoice_total=CAST(Invoice.amount as varchar(20)) FROM inserted i LEFT OUTER JOIN Invoice Invoice ON Invoice.invoiceID=i.InvoiceID select @lc_message='Attempt to UPDATE row when Posting Amount > Invoice Amount - Inserted: '+@lc_insert_amount+ ' - Deleted: '+@lc_delete_amount+ ' - sum of posted amount: '+@lc_sum_posted+ ' - Invoice Total: '+@lc_invoice_total ROLLBACK TRANSACTION RAISERROR (@lc_message, 16, 1) ENDendGO/****** Object: Trigger [check_total_insert] Script Date: 07/04/2009 10:47:27 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- ================================================create TRIGGER [dbo].[check_total_insert] on [dbo].[posting] for insert ASIF EXISTS(SELECT 1 FROM inserted i WHERE (i.Amount + (SELECT SUM(amount) from posting where posting.invoiceID=i.InvoiceID) > (SELECT Amount from Invoice WHERE invoice.InvoiceID=i.InvoiceID)) ) BEGIN ROLLBACK TRANSACTION RAISERROR ('Attempt to insert row when Posting Amount > Invoice Amount', 16, 1) ENDGO/****** Object: ForeignKey [FK_posting_invoice] Script Date: 07/04/2009 10:47:27 ******/ALTER TABLE [dbo].[posting] WITH CHECK ADD CONSTRAINT [FK_posting_invoice] FOREIGN KEY([invoiceID])REFERENCES [dbo].[invoice] ([InvoiceID])GOALTER TABLE [dbo].[posting] CHECK CONSTRAINT [FK_posting_invoice]GO/****** Object: ForeignKey [FK_posting_payment] Script Date: 07/04/2009 10:47:27 ******/ALTER TABLE [dbo].[posting] WITH CHECK ADD CONSTRAINT [FK_posting_payment] FOREIGN KEY([paymentID])REFERENCES [dbo].[payment] ([paymentID])GOALTER TABLE [dbo].[posting] CHECK CONSTRAINT [FK_posting_payment]GO |
|
|
webfred
Master Smack Fu Yak Hacker
8781 Posts |
Posted - 2009-07-04 : 13:52:44
|
You are doing ROLLBACK TRANSACTION for some conditions.You want it to work for more than one record.If there are 10 records and only one is *bad* then a ROLLBACK for all?It is not what you want to hear (read), but I would prefer not to do this logic in Database. I would like to do it front end app.Fred No, you're never too old to Yak'n'Roll if you're too young to die. |
 |
|
|
walank
Starting Member
12 Posts |
Posted - 2009-07-04 : 17:02:51
|
Yes,If one fails - rollback all I have it currently in font application but sometimes - once per few months something happends and then I have to spend few hours to find the problem... That's the reason why I want it in database.I am mainteining other big commercial db (Firebird 1.5) and they are using triggers for this kind of logic. I like it beter because when someone is manipulating raw data - triggers are watching....Can you expain why It's not good idea to have it on DB level ?Is it performace reason ?Thanks,Adam quote: Originally posted by webfred You are doing ROLLBACK TRANSACTION for some conditions.You want it to work for more than one record.If there are 10 records and only one is *bad* then a ROLLBACK for all?It is not what you want to hear (read), but I would prefer not to do this logic in Database. I would like to do it front end app.Fred No, you're never too old to Yak'n'Roll if you're too young to die.
|
 |
|
|
walank
Starting Member
12 Posts |
Posted - 2009-07-04 : 17:34:48
|
I have it working for each record using cursors (just need to add fedback on which record it faild)I know cursors shouldn't be used in triggers (because it is resource hungry) but that's the easiest way to implement....Anyone dare to convert this to non-cursor ?ALTER TRIGGER [dbo].[Update_for_each_record] ON [dbo].[posting] AFTER UPDATE AS BEGIN DECLARE @InvoiceNumber int; DECLARE @posted_amount float; DECLARE @invoice_total float; DECLARE @ICURSOR CURSOR; SET @ICURSOR =CURSOR FOR SELECT InvoiceID FROM deleted; OPEN @ICURSOR FETCH NEXT FROM @ICURSOR INTO @InvoiceNumber WHILE (@@FETCH_STATUS = 0) BEGIN --do anything you want to do for each row SELECT @posted_amount=SUM(posting.Amount) FROM posting WHERE InvoiceID=@InvoiceNumber SELECT @invoice_total=Invoice.amount FROM invoice WHERE InvoiceID=@InvoiceNumber IF @posted_amount>@invoice_total begin rollback transaction raiserror('Posted amount more than Invoice amount',16,1) end -- next record FETCH NEXT FROM @ICURSOR INTO @InvoiceNumber; END CLOSE @ICURSOR DEALLOCATE @ICURSOR; END |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-07-05 : 03:41:07
|
this will update correct ones and raiserror only for wrong onesALTER TRIGGER [dbo].[Update_for_each_record] ON [dbo].[posting] INSTEAD OF UPDATE AS BEGIN DECLARE @Errored varchar(8000)UPDATE pstSET pst.Amount=i.AmountFROM posting pstJOIN INSERTED iON i.PK=pst.PKJOIN (SELECT InvoiceID,SUM(posting.Amount) AS Total_Post_AmountFROM posting GROUP BY InvoiceID)pON p.InvoiceID=i.InvoiceIDJOIN invoice invON i.InvoiceID=inv.InvoiceIDWHERE p.Total_Post_Amount < inv.amountSELECT @Errored=COALESCE(@Errored+ ';','') + CAST (pst.PK AS varchar(10)) FROM posting pstJOIN INSERTED iON i.PK=pst.PKJOIN (SELECT InvoiceID,SUM(posting.Amount) AS Total_Post_AmountFROM posting GROUP BY InvoiceID)pON p.InvoiceID=i.InvoiceIDJOIN invoice invON i.InvoiceID=inv.InvoiceIDWHERE p.Total_Post_Amount > inv.amount IF @Errored>''raiserror('Posted amount more than Invoice amount for followed posting %s',16,1,@Errored) END |
 |
|
|
walank
Starting Member
12 Posts |
Posted - 2009-07-05 : 13:00:47
|
Thanks visakh16 for nice conversion.However I notice that raiseerror is not working. When I run bad update I see "0 records updated" - but no error...PS. I assume this line:ON i.PK=pst.PKshould be:ON i.InvoiceID=pst.InvoiceIDThanks,Adamquote: Originally posted by visakh16 this will update correct ones and raiserror only for wrong onesALTER TRIGGER [dbo].[Update_for_each_record] ON [dbo].[posting] INSTEAD OF UPDATE AS BEGIN DECLARE @Errored varchar(8000)UPDATE pstSET pst.Amount=i.AmountFROM posting pstJOIN INSERTED iON i.PK=pst.PKJOIN (SELECT InvoiceID,SUM(posting.Amount) AS Total_Post_AmountFROM posting GROUP BY InvoiceID)pON p.InvoiceID=i.InvoiceIDJOIN invoice invON i.InvoiceID=inv.InvoiceIDWHERE p.Total_Post_Amount < inv.amountSELECT @Errored=COALESCE(@Errored+ ';','') + CAST (pst.PK AS varchar(10)) FROM posting pstJOIN INSERTED iON i.PK=pst.PKJOIN (SELECT InvoiceID,SUM(posting.Amount) AS Total_Post_AmountFROM posting GROUP BY InvoiceID)pON p.InvoiceID=i.InvoiceIDJOIN invoice invON i.InvoiceID=inv.InvoiceIDWHERE p.Total_Post_Amount > inv.amount IF @Errored>''raiserror('Posted amount more than Invoice amount for followed posting %s',16,1,@Errored) END
|
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-07-05 : 13:02:58
|
| by PK i meant primary key of your posting table |
 |
|
|
|
|
|
|
|