Trouble with SQL trigger - sql-server

Need help with a trigger.
If I remove my inner joins from where clause it runs, so I'm guessing this is where the issue would be. If I use this where clause it works "WHERE oeordhdr_sql.A4GLIdentity =#id "
Any help would be appreciated. Below is the code...
ALTER trigger [dbo].[bdordermakeonhold]
on [dbo].[oeordhdr_sql]
for insert
as
declare #edi as char(1)
declare #id as numeric(9,0)
declare #ordno as char(8)
declare #ordtype as char(1)
declare #cus_no as char(12)
declare #status as char(1)
declare #ship_to_addr_3 as char(40)
set #edi=(select edi_fg from inserted)
set #id=(select a4glidentity from inserted)
set #ordno=(select ord_no from inserted)
set #ordtype=(select ord_type from inserted)
set #cus_no=(select cus_no from inserted)
set #status=(select status from inserted)
set #ship_to_addr_3=(select status from inserted)
set nocount on
if #edi is null or #edi='E'
if not exists (SELECT ID, Cus_No, State, CertificateID, Expiration FROM BDSalesTaxCerts
WHERE State = 'FL' AND #cus_no = Cus_No)
begin
UPDATE oeordhdr_sql
SET status = 'C',hold_fg = 'H'
FROM inserted AS i INNER JOIN
oeordlin_sql AS LN ON LN.ord_no = i.ord_no INNER JOIN
ARCUSFIL_SQL as CS ON i.cus_no = CS.cus_no
WHERE oeordhdr_sql.A4GLIdentity =#id and cs.state not in ('FL','PR',' ','lima') and
(LN.loc = 'SE') AND (#ship_to_addr_3 LIKE '%FL%') AND #status in ('1')
if not exists (select ID from BDInvoiceSupport where Orig_Ord_no=#ordno and orig_ord_type
=#ordtype)
begin
INSERT INTO [dbo].[BDInvoiceSupport]
([ID]
,[LastUpdate]
,[RecordRevLevel]
,[Inv_No]
,[TaxProcessingStatus]
,[Orig_Ord_no]
,[orig_ord_type]
,[InvoiceSent]
,[OnHoldReason])
select NEWID(),GETDATE(),0,inv_no,0,ord_no,ord_type,0,'Not checked yet.'
from inserted
end
end

If two rows get inserted at once, this would give you problems. You should write it with joins to the inserted table, instead of using variables.

Related

SQL Server trigger only if a field is false prior to update

I have written the trigger below that inserts values if the emailstudio column is updated. This column can be 0 or 1.
How can I write the trigger so that it only fires if the emailstudio column is changed from 0 to 1, not if it was already 1?
Thank you
ALTER TRIGGER [dbo].[RM_Est_Email_Trigger]
ON [dbo].[K3_BriefHeader]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #estimate int, #Email_Date datetime, #status int, #emailstudio bit
SET #estimate = (SELECT Estimate from inserted)
set #Email_Date = GETDATE()
SET #status = (SELECT Status from inserted)
SET #emailstudio = (SELECT EmailStudio from inserted)
IF UPDATE (EmailStudio)
BEGIN
INSERT INTO [dbo].[K3_EstimateEmailDate] ([Estimate], [Email_Date],[Status], [EmailStudio])
VALUES (#estimate, #Email_Date, #status, #emailstudio)
END
END
Insert INTO [dbo].[K3_EstimateEmailDate] (
[Estimate]
,[Email_Date]
,[Status]
,[EmailStudio]
)
SELECT Estimate
,GETDATE()
,status
,1
FROM inserted
LEFT JOIN deleted
ON deleted.<primarykey> = inserted.<primarykey>
WHERE inserted.emailstudio = 1
AND (deleted.emailstudio is null -- inserted
OR deleted.emailstudio = 0) -- updated

SQL Trigger not updating all inserted rows

SQL Trigger is not updating all the inserted rows, only few rows get updated,I am not able to understand why. The rows are are getting row ID and RateID, I have tested the trigger by making rowId entries in the Audit log
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[mytrigger]
ON [dbo].[myTable]
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #RowId int,
#RateID int,
#RateCode NVARCHAR(50)
SELECT #RateID = RateID,
#RowId = RowId
FROM inserted
// Method I found on StackOverflow
-- Update cr
-- Set cr.RateCode = r.RateCode
-- From mytable cr
-- inner join inserted on cr.RowId = inserted.RowId
-- inner join rates r on inserted.RateID = r.ID
--where cr.RowId = inserted.RowId
//Method Aaron Suggested
--UPDATE t1
--SET t1.RateCode = t2.RateCode
--FROM dbo.mytable AS t1
-- INNER JOIN dbo.rates AS t2
-- ON t1.RateID = t2.ID
-- WHERE t1.RowId = inserted.RowId
// Method I am currently using
IF #RateID IS NOT NULL
BEGIN
Select #RateCode = RateCode From rates where ID = #RateID
IF #RateCode IS NOT NULL
Update mytable Set RateCode = #RateCode Where RowId = #RowId
--UPDATE [dbo].[mytable ] SET RateCode = #RateCode FROM Inserted i WHERE mytable .RowId = i.RowId
END
END

SQL Server : calling a stored procedure using table data

I may be wording this question very poorly but I am not 100% sure what I need to question.
I am trying to iterate over rows in a table and call a stored procedure using the data from the rows.
This is the code I already have, the problem with this is a timing issue (1000 rows takes around 1 minute);
--Set up a temp table with all non email alerts
SELECT TOP(1000)
RowNum = ROW_NUMBER() OVER(ORDER BY AlertID),
a.*, i.ImgData
INTO
#temp
FROM
dbo.ALERTS a
JOIN
dbo.IMAGES i ON i.VehicleID = a.VehicleID
WHERE
a.EmailImageSent = 0 OR a.EmailSent = 0
DECLARE #MaxRownum INT
SET #MaxRownum = (SELECT MAX(RowNum) FROM #temp)
DECLARE #Iter INT
SET #Iter = (SELECT MIN(RowNum) FROM #temp)
DECLARE #ImgData VARBINARY(MAX)
WHILE #Iter <= #MaxRownum
BEGIN
SELECT #VehicleID = VehicleID, #ImgData = ImgData
FROM #temp
WHERE RowNum = #Iter
IF #ImgData IS NOT NULL
BEGIN
EXEC dbo.someProcedure #VehicleID, #ImgData
--SELECT 'Image data found for', #VehicleID, #ImgData
END
SET #Iter = #Iter + 1
END
DROP TABLE #temp
Is there anyway I can run the stored procedure (dbo.someProcedure) while using a set based statement as the input?
Sorry if this has been asked before, I've had a look and couldn't find an answer or if this question isn't informative enough.
Thanks in advance
AFAIK sp_send_dbmail will need to be called once for each email, so either you have a loop here or you have a loop inside dbo.someProcedure.
Still I think that you could make some improvements. Use a FAST_FORWARD cursor rather than creating iteration variables and returning to the table each time to find the next row (thus creating 1000 table scans). Don't store redundant data in your #temp table, only what you need. This makes the table quicker to read.
Try this:
--Set up a temp table with all non email alerts
Create Table #temp (VehicleID int Primary Key Clustered, ImgData varbinary(max));
INSERT INTO #temp (VehicleID, ImgData)
SELECT TOP(1000)
a.VehicleID, i.ImgData
FROM
dbo.ALERTS a
JOIN
dbo.IMAGES i ON i.VehicleID = a.VehicleID
WHERE
a.EmailImageSent = 0 OR a.EmailSent = 0;
DECLARE #VehicleID int;
DECLARE #ImgData VARBINARY(MAX);
DECLARE Alert_Cursor Cursor Fast_Forward For (
Select VehicleID, ImgData From #temp);
OPEN Alert_Cursor;
FETCH NEXT FROM Alert_Cursor INTO #VehicleID, #ImgData;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #ImgData IS NOT NULL
EXEC dbo.someProcedure #VehicleID, #ImgData;
FETCH NEXT FROM Alert_Cursor INTO #VehicleID, #ImgData;
END
CLOSE Alert_Cursor;
DEALLOCATE Alert_Cursor;
DROP TABLE #temp;

SQL Trigger, sub query returning more then one value.

I m having a trouble with my trigger, it works for single row update, but for multiple updates it gives error that sub query is returning more then one value. how to handle this.
GO
ALTER TRIGGER [dbo].[OnpaymentUpdate]
ON [dbo].[paymentData]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #customerID NCHAR(50), #lastpaymentDate DATETIME, #stat nchar(50), #month int;
SET #customerID= (SELECT customerID FROM inserted)
SET #stat= (SELECT stat FROM inserted) --table inserted contains inserted rows (or new updated rows)
set #lastpaymentDate = (SELECT MAX(paymentDate) FROM paymentReceipt where customerID=#customerID)
SET #month= (SELECT DATEDIFF(MONTH, #lastpaymentDate,GETDATE()))
DECLARE #balance BIGINT
SET #balance =
(
SELECT (totalprice-(paidAmount+concession))
FROM paymentData
WHERE customerID = #customerID
)
Declare #paid int
SET #paid =
(
SELECT paidAmount
FROM paymentData
WHERE customerID = #customerID
)
UPDATE PaymentData
SET balanceAmount = #balance ,
lastpaymentDate=#lastpaymentDate
WHERE customerID = #customerID
if (#month >=2 and #stat!='Cancel' and #stat!='Refund' And #stat!='Refunded' and #stat!='Transfered' and #stat!='Transfer')
Begin
IF (#month <2 and #stat='Defaulter')
SET #stat='Regular'
IF (#balance<=0 and #paid >0)
SET #stat='Payment Completed'
else
SET #stat='Defaulter'
End
else
Begin
if #stat='Refund'
Set #stat='Refunded'
if #stat='Cancled'
Set #stat='Cancel'
if #stat='Transfer'
Set #stat='Transfered'
End
UPDATE PaymentData
SET stat =#stat
WHERE customerID = #customerID
END
I wouldn't have a trigger at all. I'd rebuild your table and then create a view that mimics your current table definition. Of course, I don't know your current tables, so I can only write my best guess for now. And as I said, I don't understand your status logic at the bottom where #month can apparently be, simultaneously, both >=2 and <2, so I've left that portion incomplete:
create table dbo._PaymentData (
CustomerID nchar(50) not null,
_Status nchar(50) not null,
TotalPrice bigint not null,
PaidAmount bigint not null,
Concession bigint not null,
Balance as TotalPrice - (PaidAmount + Concession)
)
go
create view dbo.PaymentData
with schemabinding
as
with RecentReceipts as (
select CustomerID,MAX(PaymentDate) as LastPayment from dbo.PaymentReceipt group by CustomerID
), MonthsDelinquent as (
select CustomerID,LastPayment,DATEDIFF(month,LastPayment,CURRENT_TIMESTAMP) as Months from RecentReceipts
)
select
pd.CustomerID,
TotalPrice,
PaidAmount,
Concession,
Balance,
LastPayment,
CASE
WHEN _Status in ('Cancel','Refund','Refunded','Transfered','Transfer')
THEN _Status
WHEN md.Months > 2 and Balance<= 0 and PaidAmount > 0
THEN 'Payment Complete'
--More conditions here to work out the actual status
END as Status
from
dbo._PaymentData pd
left join
MonthsDelinquent md
on
pd.CustomerID = md.CustomerID
go
And now, we don't need the trigger - the table and/or the view are always up correct (although a trigger may be required on the view to allow Status/_Status to be updated - it's not currently clear whether that's necessary or whether _Status actually needs to exist at all)
Could their be more than one CustomerID added in the process? This line is trouble:
SET #customerID= (SELECT customerID FROM inserted)
SET #stat= (SELECT stat FROM inserted) --table inserted contains inserted
If customerID and stat are guaranteed to be consistent for all rows, you can fix it with a MAX, like:
SET #customerID= (SELECT MAX(customerID) FROM inserted)
SET #stat= (SELECT MAX(stat) FROM inserted) --table inserted contains inserted
But, if those items aren't guaranteed to be consistent for all rows inserted, you will run into trouble. If that's the case, you'll need a cursor to cursor through the values.
Also Change to this:
SET #balance =
(
SELECT SUM( (totalprice-(paidAmount+concession)) )
FROM paymentData
WHERE customerID = #customerID
)
Declare #paid int
SET #paid =
(
SELECT SUM(paidAmount)
FROM paymentData
WHERE customerID = #customerID
)

how to insert into table but only if the record doesnt exist

I've got a table that stores the following:
JobID
ValidationItemID
CreatedBy
I want to be able to insert into this table (a predefined template) but only add rows that dont exist. What I mean by dont exist is the combination of JobID and ValidationItemID make the row unique. My procedure passes in a JobID, but I cannot pass in a validation item ID as I pull this column as part of the template...
Something to this effect:
CREATE PROCEDURE insTemplate
#JobID varchar(50),
#Login varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO
ValidationItemSignOff
(
JobID,
ValidationItemID,
CreatedBy
)
SELECT
DISTINCT
#JobID,
vi.ValidationItemID,
#Login
FROM
RunOffAnswer roa
INNER JOIN
Method m ON m.MethodID = roa.MethodID
INNER JOIN
RunOffValidationItem vi ON vi.ValidationItemID = m.ValidationItemID
WHERE
vi.Inactive=0
AND NOT EXISTS(SELECT * FROM ValidationItemSignOff WHERE JobID=#JobID AND vi.ValidationItemID ???
END
GO
I dont know how to phrase the where condition so that it doesn't reinsert the same JobID and ValidationItemID. Lets say I have inside the table:
Job ValidationItem
Job A 1
Job A 2
Job A 5
And I have a template with the following:
ValidationItem
1
2
3
4
5
6
When I run my stored procedure it should only insert values 3,4,6 from the template table, for the job id... So I need help with my where condition.
I think my issue is I cannot use NOT EXISTS, maybe I need to join back to this ValidationItemSignOff table itself on JobID and ValidationItemID where ValidationItemID is NULL, maybe like this:
CREATE PROCEDURE insTemplate
#JobID varchar(50),
#Login varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO
ValidationItemSignOff
(
JobID,
ValidationItemID,
CreatedBy
)
SELECT
DISTINCT
#JobID,
vi.ValidationItemID,
#Login
FROM
RunOffAnswer roa
INNER JOIN
Method m ON m.MethodID = roa.MethodID
INNER JOIN
RunOffValidationItem vi ON vi.ValidationItemID = m.ValidationItemID
RIGHT OUTER JOIN
ValidationItemSignOff viso ON viso.JobID = #JobID
AND viso.ValidationItemID = vi.ValidationItemID
WHERE
vi.Inactive=0
AND viso.ValidationItemID IS NULL
END
GO
Got it I think
Replacing the right join with this:
LEFT JOIN
ValidationItemSignOff viso
ON viso.JobID = #JobID
AND viso.ValidationItemID = vi.ValidationItemID
If you're on 2008 or above...
MERGE INTO ValidationItemSignOff As Target
USING (SELECT DISTINCT #JobID, vi.ValidationItemID, #Login
FROM RunOffAnswer roa INNER JOIN
Method m
ON m.MethodID = roa.MethodID INNER JOIN
RunOffValidationItem vi
ON vi.ValidationItemID = m.ValidationItemID
WHERE vi.Inactive = 0) As Source (JobID, ValidationItemID, Login)
ON Target.JobID = Source.JobID
AND Target.ValidationItemID = Source.ValidationItemID
WHEN NOT MATCHED BY TARGET THEN
INSERT (JobID, ValidationItemID, CreatedBy)
VALUES (Source.JobID, Source.ValidationItemID, Source.Login);
Disclaimer: I may have not got the syntax spot on here.
I got it with this:
ALTER PROCEDURE insSignOffTemplate
#JobID varchar(50),
#Login varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO
ValidationItemSignOff
(
JobID,
ValidationItemID,
CreatedBy
)
SELECT
DISTINCT
#JobID,
vi.ValidationItemID,
#Login
FROM
RunOffAnswer roa
INNER JOIN
Method m
ON
m.MethodID = roa.MethodID
INNER JOIN
RunOffValidationItem vi
ON
vi.ValidationItemID = m.ValidationItemID
LEFT JOIN
ValidationItemSignOff viso
ON viso.JobID = #JobID AND viso.ValidationItemID = vi.ValidationItemID
WHERE
vi.Inactive=0
AND viso.ValidationItemID IS NULL
END
GO

Resources