Stored Procedure works when executed manually but not via trigger - sql-server

So I created a Stored Procedure in SQL that does 4 things
Create Order into Customer Order table
Create Order lines on Customer Order Line table
Update Auto number column by taking current value and adding 1
Update Purchase Order with Customer Order ID
Sends email to notify that an order has been created.
It works awesome if I execute each part separately or execute the whole Stored Procedure manually by sending command EXEC dbo.POIMPORT_UK #PO_NUM = 123456
But when I create a PO and it triggers the inserts, query 1,3,4,5 work but 2 doesn't for some reason. I can only get it to go if I fire off that procedure manually. Any thoughts?
USE [RIPTST]
GO
/****** Object: StoredProcedure [dbo].[POIMPORT_UK] Script Date: 8/20/2018 11:21:23 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[POIMPORT_UK]
#PO_NUM NVARCHAR(15)
AS
SET NOCOUNT ON
--For synchronization machine id placement
--Query 1
INSERT INTO CUSTOMER_ORDER(ID, CUSTOMER_ID, SITE_ID, SELL_RATE, BUY_RATE,
TERMS_NET_TYPE, TERMS_DISC_TYPE, FREIGHT_TERMS, BACK_ORDER, STATUS,
POSTING_CANDIDATE, MARKED_FOR_PURGE, CURRENCY_ID, CUSTOMER_PO_REF,
WAREHOUSE_ID, DESIRED_SHIP_DATE) SELECT (SELECT Next_number FROM
NEXT_NUMBER_GEN where rowid =
'72'),'ABECO','101RIPUS','1.0','1.0','A','A','P','N','F','N','N','(USD)
$',ID,'CROM',Getdate() FROM PURCHASE_ORDER WHERE ID = #PO_NUM
--Query 2
INSERT INTO CUST_ORDER_LINE
(CUST_ORDER_ID,LINE_NO,PART_ID,LINE_STATUS,ORDER_QTY,USER_ORDER_QTY,
SELLING_UM,UNIT_PRICE,SITE_ID,MISC_REFERENCE,PRODUCT_CODE,COMMODITY_CODE,
DRAWING_ID,DRAWING_REV_NO,MAT_GL_ACCT_ID,LAB_GL_ACCT_ID,BUR_GL_ACCT_ID,
SER_GL_ACCT_ID,GL_REVENUE_ACCT_ID,TOTAL_AMT_ORDERED,ENTERED_BY,WAREHOUSE_ID)
SELECT(select id from customer_order where CUSTOMER_PO_REF = #PO_NUM),
LINE_NO,PURC_ORDER_LINE.PART_ID,'A',ORDER_QTY,USER_ORDER_QTY,
PURCHASE_UM,PURC_ORDER_LINE.UNIT_PRICE,'101RIPUS',PART.DESCRIPTION,
PART.PRODUCT_CODE,PART.COMMODITY_CODE,PART.DRAWING_ID,PART.DRAWING_REV_NO,
PART_SITE.MAT_GL_ACCT_ID,PART_SITE.LAB_GL_ACCT_ID,PART_SITE.BUR_GL_ACCT_ID,
PART_SITE.SER_GL_ACCT_ID,
(SELECT REV_GL_ACCT_ID FROM PRODUCT WHERE CODE = PART.PRODUCT_CODE),
USER_ORDER_QTY*PURC_ORDER_LINE.UNIT_PRICE,'SYSADM',
PART_SITE.PRIMARY_WHS_ID From PURC_ORDER_LINE
Inner Join PART On PART.ID = PURC_ORDER_LINE.PART_ID
Inner Join PART_SITE On PART_SITE.PART_ID = PART.ID
WHERE PURC_ORDER_ID = #PO_NUM AND PART_SITE.sITE_ID = '101RIPUS'
--Query 3
Update NEXT_NUMBER_GEN Set Next_number = Next_number + 1 where rowid = '72'
--Query 4
Update PURCHASE_ORDER Set SALES_ORDER_ID = (select id from customer_order where CUSTOMER_PO_REF = #PO_NUM) where id = #PO_NUM
--Query 5
Declare #PO NVARCHAR(15) = #PO_NUM
Declare #CO NVARCHAR(15) = (select id from customer_order where CUSTOMER_PO_REF = #PO)
Declare #MYBODY VARCHAR(MAX) = 'Hello Test CSR,
A new internal order has been created for Ripley UK.
Test US Customer Order Number: ' + #CO +
'
Test UK Purchase Order Number: ' + #PO
EXEC msdb.dbo.sp_send_dbmail #profile_name='office365',
#recipients='test#test.com',
#subject='Test UK - Internal Order',
#body= #MYBODY
SET NOCOUNT OFF
Insert Trigger
USE [RIPTST]
GO
/****** Object: Trigger [dbo].[INSERT_PURCHASE_ORDER] Script Date: 8/20/2018 1:42:15 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER trigger [dbo].[INSERT_PURCHASE_ORDER] ON [dbo].[PURCHASE_ORDER] FOR INSERT AS
DECLARE
#nRcd INT,
#ID NVARCHAR(15),
#VENDOR_ID NVARCHAR(15),
#SITE_ID NVARCHAR(15),
#STATUS NCHAR,
#TOTAL_AMT_ORDERED DEC(15,2),
#TOTAL_AMT_RECVD DEC(15,2),
#SELL_RATE DEC(17,8),
#nCurrDigits INT,
#sEntityID NVARCHAR(15),
#ORDER_DATE DATETIME
SELECT #nRcd = 0
SET NOCOUNT ON
DECLARE PURCHASE_ORDER_INS CURSOR LOCAL FOR SELECT ID, VENDOR_ID, STATUS, TOTAL_AMT_ORDERED, TOTAL_AMT_RECVD, SELL_RATE, ORDER_DATE, SITE_ID FROM INSERTED
OPEN PURCHASE_ORDER_INS
FETCH PURCHASE_ORDER_INS INTO #ID, #VENDOR_ID, #STATUS, #TOTAL_AMT_ORDERED, #TOTAL_AMT_RECVD, #SELL_RATE, #ORDER_DATE, #SITE_ID
WHILE (#nRcd = 0 and ##FETCH_STATUS <> -1)
BEGIN
EXEC EXE_DETECT_EVENT 'P', #ID, NULL, NULL, 'I'
If #TOTAL_AMT_ORDERED + #TOTAL_AMT_RECVD != 0
SELECT #nRcd = 30881
If #nRcd = 0 And (#STATUS = 'R' Or #STATUS = 'F') And #TOTAL_AMT_ORDERED > #TOTAL_AMT_RECVD
BEGIN
select #nCurrDigits = c.i_curr_digits, #sEntityID = s.entity_id from CURRENCY c, ACCOUNTING_ENTITY ae, SITE s where s.id = #SITE_ID and ae.id = s.entity_id and ae.functional_currency_id = c.id
IF NOT EXISTS ( SELECT VENDOR_ID FROM VENDOR_ENTITY WHERE vendor_id = #VENDOR_ID and entity_id = #sEntityID )
INSERT INTO VENDOR_ENTITY ( VENDOR_ID, ENTITY_ID ) VALUES ( #VENDOR_ID, #sEntityID )
update VENDOR_ENTITY set
total_open_orders = total_open_orders + ROUND((#TOTAL_AMT_ORDERED - #TOTAL_AMT_RECVD) * #SELL_RATE, #nCurrDigits),
open_order_count = open_order_count + 1
where vendor_id = #VENDOR_ID and entity_id = #sEntityID
END
UPDATE VENDOR set last_order_date = #ORDER_DATE where id = #VENDOR_ID
FETCH PURCHASE_ORDER_INS INTO #ID, #VENDOR_ID, #STATUS, #TOTAL_AMT_ORDERED, #TOTAL_AMT_RECVD, #SELL_RATE, #ORDER_DATE, #SITE_ID
END
BEGIN
IF #VENDOR_ID = 'RIP01' AND #SITE_ID = '111RIPUK'
EXEC dbo.POIMPORT_UK #PO_NUM = #ID
END
DEALLOCATE PURCHASE_ORDER_INS
IF (#nRcd <> 0) RAISERROR('VMFG-%d error in trigger INSERT_PURCHASE_ORDER', 16, -1, #nRcd)
IF (#nRcd <> 0 Or ##ERROR <> 0) ROLLBACK TRANSACTION

Related

Getting error when executing the stored procedure using SQL Server

I get an error
Subquery returned more than 1 value
when executing a stored procedure. I need to copy data from the database I am building to the live database. The code inserted the data into TestTextmessage table and updateed TextMessage table. The error occurred when try to insert into the TestMobileRecipient table that is the reason why the table is empty.
The table structure and code are below
Stored procedure
CREATE PROCEDURE [dbo].[TestSendITMessage]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #i int
DECLARE #idmessage int
DECLARE #numrows int
DECLARE #messagehold TABLE
(
idx SMALLINT PRIMARY KEY IDENTITY(1,1),
MessageId INT
)
DECLARE #InsertedID INT
INSERT INTO #messagehold
SELECT DISTINCT Id
FROM [MPFT_SendIT].dbo.TextMessage
WHERE DontSendBefore < GETDATE()
AND DateSent IS NULL
AND MessageSent = 0
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #messagehold)
IF #numrows > 0
WHILE (#i <= (SELECT MAX(idx) FROM #messagehold))
BEGIN
SET #idmessage = (SELECT MessageId FROM #messagehold WHERE idx = #i)
--Do something with Id here
PRINT #idmessage
INSERT INTO [dbo].[TestTextMessage] ([Origin], [MessageBody], [MessageSent], [DateCreated], DontSendBefore)
SELECT
'LogIT', MessageBody, 0, GETDATE(), DontSendBefore
FROM
[MPFT_SendIT].dbo.TextMessage
WHERE Id = #idmessage
SET #InsertedID = SCOPE_IDENTITY();
INSERT INTO [dbo].[TestMobileRecipient] ([MessageId], MobileNumber])
VALUES (#InsertedID, (SELECT MobileNumber FROM MobileRecipient
WHERE MessageId = #idmessage))
UPDATE TextMessage
SET DateSent = GETDATE(),
MessageSent = 1
WHERE Id = #idmessage
SET #i = #i + 1
END
END
the error message is very clear. Your sub-query SELECT MobileNumber FROM MobileRecipient WHERE MessageId= #idmessage is returning more than 1 row
Change the insertion of table TestMobileRecipient to following
Insert into [dbo].[TestMobileRecipient]
(
[MessageId]
,[MobileNumber]
)
SELECT #InsertedID
, MobileNumber
FROM MobileRecipient
WHERE MessageId= #idmessage
You should update your this line
SET #idmessage = (SELECT MessageId FROM #messagehold WHERE idx = #i)
with
SET #idmessage = (SELECT top 1 MessageId FROM #messagehold WHERE idx = #i)

SQL Server cursor - cannot assign variable properly [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I use SQL Server 2016. I need to move users from a legacy system to a new one. But before bringing all users from the legacy system, I need to check if they do not already exist in our new system. Such a determination is done based on comparison of users' email addresses in each of the system.
So if a user does not exist in the new system, I need to insert such a record into the new system from the legacy one. But if user does exist, I need to update some columns in the new system with data from the legacy one.
To accomplish it I'm using a cursor with SCOPE_IDENTITY().
Also I need to log newly inserted and existing updated records in each cursor iteration. The problem is that my code does not differentiate new and existing records hence it inserts all user id in the Log table twice. One time in case the userID (#ContactID) IS NULL (not existing in the new system) and another when userID (#ContactID) IS NOT NULL - existing in the new system.
In my sample below I have 1 records that does not exists in the new system and 3 do match already. So in the IF (#CoantactID IS NULL) I meant to insert only that newly inserted into the MyDB.dbo.Contact table record and in the IF (#CoantactID IS NOT NULL) insert into the Log table only the tree records matched (existing) in the new system.
But the problem is that it inserts all four ContactIDs into the log table even in the this IF (#ContactID IS NULL) amd then again for in IF (#ContactID IS NOT NULL)
;USE [MyDB];
GO
-- exec dbo.sp_UserMigration_Users_Copy
DROP PROCEDURE IF EXISTS dbo.sp_UserMigration_Users_Copy
GO
;USE [MyDB];
GO
CREATE PROCEDURE dbo.sp_UserMigration_Users_Copy
#UserID UNIQUEIDENTIFIER = NULL
--,#ContactID INT
AS
DECLARE #Email nvarchar(100),
#ContactID INT;
-- #UserID UNIQUEIDENTIFIER,
DECLARE #SysID INT
SET #SysId = 17511; -- system contactID
---- creating log table
--CREATE TABLE #T
--(
-- UserID UNIQUEIDENTIFIER NOT NULL,
-- Email NVARCHAR(50) NOT NULL
--);
SELECT * INTO #T
FROM MyDB.dbo.User
WHERE UserID IN (
'0604C514',
'C1FDAF34',
'23BABE2D',
'EBA21D10'
);
IF NOT EXISTS (select * from MyDB.sys.tables where name = N'UserIDContactIDMigrationLog')
CREATE TABLE MyDB.dbo.UserIDContactIDMigrationLog
(
UserID UNIQUEIDENTIFIER /* CONSTRAINT [PK_UserIDContactIDMigrationLog_UserID] PRIMARY KEY */ NOT NULL, -- somehow inserts duplicate UserIDs
ContactId INT /*UNIQUE CONSTRAINT [UNIQUE_ContactId] */ NOT NULL,
CreatedDt DATETIME2 NULL,
UpdatedDt DATETIME2 NULL,
UpdatedFlag BIT /*CONSTRAINT [DF_MigratedFlag] DEFAULT(0) */ NULL
);
-- -----------------------------------------------------
-- Cursor: For all contacts to be migrated
-- -----------------------------------------------------
IF (SELECT CURSOR_STATUS('global','user_cursor')) >= -1
BEGIN
IF (SELECT CURSOR_STATUS('global','user_cursor')) > -1
BEGIN
CLOSE user_cursor
END
DEALLOCATE user_cursor
END
DECLARE user_cursor CURSOR
FOR
SELECT a.UserID, LTRIM(RTRIM(a.Email)) AS Email
FROM #T a WITH (NOLOCK)
--WHERE a.UserID = #UserID
-- begin cursor loop
OPEN user_cursor
FETCH NEXT FROM user_cursor INTO #UserID, #Email
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #ContactID = (
SELECT c.ContactId
FROM MyDB.dbo.Contact c
LEFT OUTER JOIN MyDB.dbo.Login l ON c.ContactId = l.ContactId
WHERE (LTRIM(RTRIM(c.ContactEmailTx)) = #Email
OR LTRIM(RTRIM(l.ContactLoginNameTx)) = #Email
--OR l.ContactLoginNameTx LIKE #Email+'%' -- this concept does not work in case of leading space at the ContactLoginNameTx so need to use the code below
OR SUBSTRING(LTRIM(RTRIM(l.ContactLoginNameTx)), -1, CHARINDEX('.INACTIVE.', l.ContactLoginNameTx)) = #Email)
AND (c.ContactEmailTx != '' OR c.ContactEmailTx IS NOT NULL OR l.ContactLoginNameTx != '' OR l.ContactLoginNameTx IS NOT NULL)
)
-- check if a contact is new
IF (#ContactID IS NULL)
BEGIN
-- -----------------------------------------------------
-- MyDB.dbo.Contact
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Contact]
(
[ContactFirstNameTx],
[ContactLastNameTx],
[ContactEmailTx],
[ContactTitleTx],
[ContactCreateDt],
[ContactCreateByID],
[ContactCreateLoginTypeID]
)
SELECT
[FirstName],
[LastName],
[Email],
[Title],
--[AccountId],
[UserCreatedDate],
#SysId AS [ContactCreateByID], -- as as flag for import [ContactCreateLoginTypeID]
-10 AS [ContactCreateLoginTypeID]
FROM #T o WITH (NOLOCK)
WHERE UserID = #UserID
SET #ContactID = SCOPE_IDENTITY()
END
-- select * from [MyDB].[dbo].[Contact] where contactid in ( 1051364, 466440, 560466, 618576)
-- -----------------------------------------------------
--MyDB.dbo.Login
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Login]
(
ContactID,
[ContactLoginNameTx], -- V.C. this is email. the field is has a unique constraint
[ContactLoginActiveIn],
[ContactLoginCreateDt],
[ContactLoginCreateByID],
[ContactLoginCreateLoginTypeID],
[ContactLoginPasswordLastChangeDt],
[ContactLoginLastLoginDt],
[ContactLoginPasswordExclusionIn] -- this is not nullable and BIT
)
SELECT
#ContactID AS ContactID,
[Email],
CASE WHEN [UserStatusID] IN (1, 3) THEN 1 ELSE 0 END AS [ContactLoginActiveIn], -- v.c. in Onvia 1 is Active, 2 - Inactive, 3 - Invited, 4 - Inactive By System, 5 - Pending Registration
[UserCreatedDate],
#SysId AS ContactLoginCreateByID, -- as as flag for Onvia import[ContactCreateLoginTypeID]
-10 AS [ContactLoginCreateLoginTypeID],
[UserLastPasswordChangedDate],
[UserLastLoginDate],
0 as ContactLoginPasswordExclusionIn -- this is not nullable and BIT
FROM #T o WITH (NOLOCK)
WHERE UserID = #UserID
AND NOT EXISTS (select * from MyDB.dbo.Login z where z.ContactID = #ContactID)
-- -----------------------------------------------------
-- Activate any inactive users
-- -----------------------------------------------------
IF EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 0 and ContactID = #ContactID)
AND NOT EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 1 and ContactID = #ContactID)
BEGIN
UPDATE [MyDB].[dbo].[Login]
SET ContactLoginNameTx = #Email,
ContactLoginActiveIn = (select case when [UserStatusID] IN (1, 3) then 1 else 0 end
from #T o where o.UserID = #UserID)
WHERE ContactID = #ContactID
END
-- -----------------------------------------------------
--MyDB.dbo.ContactPhoneNumber
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[PhoneNumber]
(
ContactID,
PhoneNumberTypeID,
ContactPhoneNumberValueTx
)
SELECT
#ContactID AS ContactID,
1 AS PhoneNumberTypeID,
ISNULL([PhoneNumber1],'') AS ContactPhoneNumberValueTx
FROM #T o WITH (NOLOCK)
WHERE o.UserID = #UserID
AND NOT EXISTS (select * from [MyDB].[dbo].[PhoneNumber] z where z.ContactID = #ContactID);
-- -----------------------------------------------------
--MyDB.dbo.ContactOrg
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Org]
(
ContactID,
OrgID
)
SELECT
#ContactID AS ContactID,
b.OrgID AS OrgID
FROM #T o WITH (NOLOCK)
INNER JOIN ImportQueue.dbo.OnviaAccountIDOrgIDMigrationLog b WITH (NOLOCK) ON o.AccountId = b.OnviaAccountID
WHERE o.UserID = #UserID
AND NOT EXISTS (select * from [MyDB].[dbo].[Org] z where z.ContactID = #ContactID);
-- -----------------------------------------------------
---- MyDB.dbo.UserIDContactIDMigrationLog
---- log output for new users
-- -----------------------------------------------------
INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
(
UserID,
ContactId,
CreatedDt,
UpdatedFlag
)
VALUES
(
#UserID,
#ContactID,
GETDATE(),
0
)
-- -----------------------------------------------------
-- EXISTING MATCHED USERS
-- -----------------------------------------------------
-- check if a contact is existing
IF (#ContactID IS NOT NULL)
BEGIN
-- -----------------------------------------------------
-- MyDB.dbo.Contact
-- -----------------------------------------------------
UPDATE MyDB.dbo.Contact
SET ContactFirstNameTx =
CASE
WHEN ContactFirstNameTx NOT IN ('', NULL) THEN c.FirstName
ELSE ContactFirstNameTx
END,
ContactLastNameTx =
CASE
WHEN ContactLastNameTx IN ('', NULL) THEN c.LastName
ELSE ContactLastNameTx
END,
ContactEmailTx =
CASE
WHEN ContactEmailTx IN ('', NULL) THEN c.Email
ELSE ContactEmailTx
END,
ContactTitleTx =
CASE
WHEN ContactTitleTx IN ('', NULL) THEN c.Title
ELSE ContactTitleTx
END,
[ContactCreateDt] =
CASE
WHEN ContactCreateDt IN ('', NULL) THEN c.UserCreatedDate
ELSE ContactCreateDt
END,
[ContactModifyByID] = #SysId,
[ContactModifyLoginTypeID] = - 10
FROM #T c
WHERE UserID = #UserID
AND ContactID = #ContactID;
-- -----------------------------------------------------
---- MyDB.dbo.UserIDContactIDMigrationLog
---- log output for existing matched users
-- -----------------------------------------------------
INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
(
UserID,
ContactId,
UpdatedDt,
UpdatedFlag
)
VALUES
(
#UserID,
#ContactID,
GETDATE(),
1
);
FETCH NEXT FROM user_cursor INTO #UserID, #Email
-- end cursor loop
END
END
CLOSE user_cursor
DEALLOCATE user_cursor
GO
Instead of Cursors try the below code.
- exec dbo.sp_UserMigration_Users_Copy
DROP PROCEDURE IF EXISTS dbo.sp_UserMigration_Users_Copy
GO
;USE [MyDB];
GO
CREATE PROCEDURE dbo.sp_UserMigration_Users_Copy
#UserID UNIQUEIDENTIFIER = NULL
--,#ContactID INT
AS
DECLARE #Email nvarchar(100),
#ContactID INT;
DECLARE #SysID INT
SET #SysId = 17511;
CREATE TABLE #T
(
ID INT IDENTITY(1,1) NOT NULL,
UserID NVARCHAR(50)NOT NULL,
Email NVARCHAR(50) NOT NULL
);
INSERT INTO #T
SELECT *
FROM MyDB.dbo.User
WHERE UserID IN (
'0604C514',
'C1FDAF34',
'23BABE2D',
'EBA21D10'
);
IF NOT EXISTS (select * from MyDB.sys.tables where name = N'UserIDContactIDMigrationLog')
CREATE TABLE MyDB.dbo.UserIDContactIDMigrationLog
(
UserID UNIQUEIDENTIFIER /* CONSTRAINT [PK_UserIDContactIDMigrationLog_UserID] PRIMARY KEY */ NOT NULL, -- somehow inserts duplicate UserIDs
ContactId INT /*UNIQUE CONSTRAINT [UNIQUE_ContactId] */ NOT NULL,
CreatedDt DATETIME2 NULL,
UpdatedDt DATETIME2 NULL,
UpdatedFlag BIT /*CONSTRAINT [DF_MigratedFlag] DEFAULT(0) */ NULL
);
DECLARE #COUNT INT
DECLARE #I INT = 1
DECLARE #UserID NVARCHAR(50) ;
DECLARE #Email NVARCHAR(50)
SELECT #COUNT = COUNT(*) FROM #T
WHILE(#I <= #COUNT)
BEGIN
SELECT #UserID = UserID, #Email= LTRIM(RTRIM(Email)) FROM #T WHERE ID = #I
SELECT #ContactID = (
SELECT c.ContactId
FROM MyDB.dbo.Contact c
LEFT OUTER JOIN MyDB.dbo.Login l ON c.ContactId = l.ContactId
WHERE (LTRIM(RTRIM(c.ContactEmailTx)) = #Email
OR LTRIM(RTRIM(l.ContactLoginNameTx)) = #Email
--OR l.ContactLoginNameTx LIKE #Email+'%' -- this concept does not work in case of leading space at the ContactLoginNameTx so need to use the code below
OR SUBSTRING(LTRIM(RTRIM(l.ContactLoginNameTx)), -1, CHARINDEX('.INACTIVE.', l.ContactLoginNameTx)) = #Email)
AND (c.ContactEmailTx != '' OR c.ContactEmailTx IS NOT NULL OR l.ContactLoginNameTx != '' OR l.ContactLoginNameTx IS NOT NULL)
)
-- check if a contact is new
IF (#ContactID IS NULL)
BEGIN
-- -----------------------------------------------------
-- MyDB.dbo.Contact
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Contact]
(
[ContactFirstNameTx],
[ContactLastNameTx],
[ContactEmailTx],
[ContactTitleTx],
[ContactCreateDt],
[ContactCreateByID],
[ContactCreateLoginTypeID]
)
SELECT
[FirstName],
[LastName],
[Email],
[Title],
--[AccountId],
[UserCreatedDate],
#SysId AS [ContactCreateByID], -- as as flag for Onvia import[ContactCreateLoginTypeID]
-10 AS [ContactCreateLoginTypeID]
FROM #T o WITH (NOLOCK)
WHERE UserID = #UserID
SET #ContactID = SCOPE_IDENTITY()
END
-- select * from [MyDB].[dbo].[Contact] where contactid in ( 1051364, 466440, 560466, 618576)
-- -----------------------------------------------------
--MyDB.dbo.Login
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Login]
(
ContactID,
[ContactLoginNameTx], -- V.C. this is email. the field is has a unique constraint
[ContactLoginActiveIn],
[ContactLoginCreateDt],
[ContactLoginCreateByID],
[ContactLoginCreateLoginTypeID],
[ContactLoginPasswordLastChangeDt],
[ContactLoginLastLoginDt],
[ContactLoginPasswordExclusionIn] -- this is not nullable and BIT
)
SELECT
#ContactID AS ContactID,
[Email],
CASE WHEN [UserStatusID] IN (1, 3) THEN 1 ELSE 0 END AS [ContactLoginActiveIn], -- v.c. in Onvia 1 is Active, 2 - Inactive, 3 - Invited, 4 - Inactive By System, 5 - Pending Registration
[UserCreatedDate],
#SysId AS ContactLoginCreateByID, -- as as flag for Onvia import[ContactCreateLoginTypeID]
-10 AS [ContactLoginCreateLoginTypeID],
[UserLastPasswordChangedDate],
[UserLastLoginDate],
0 as ContactLoginPasswordExclusionIn -- this is not nullable and BIT
FROM #T o WITH (NOLOCK)
WHERE UserID = #UserID
AND NOT EXISTS (select * from MyDB.dbo.Login z where z.ContactID = #ContactID)
-- -----------------------------------------------------
-- Activate any inactive users
-- -----------------------------------------------------
IF EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 0 and ContactID = #ContactID)
AND NOT EXISTS (select * from MyDB.dbo.Login where ContactLoginActiveIn = 1 and ContactID = #ContactID)
BEGIN
UPDATE [MyDB].[dbo].[Login]
SET ContactLoginNameTx = #Email,
ContactLoginActiveIn = (select case when [UserStatusID] IN (1, 3) then 1 else 0 end
from #T o where o.UserID = #UserID)
WHERE ContactID = #ContactID
END
-- -----------------------------------------------------
--MyDB.dbo.ContactPhoneNumber
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[PhoneNumber]
(
ContactID,
PhoneNumberTypeID,
ContactPhoneNumberValueTx
)
SELECT
#ContactID AS ContactID,
1 AS PhoneNumberTypeID,
ISNULL([PhoneNumber1],'') AS ContactPhoneNumberValueTx
FROM #T o WITH (NOLOCK)
WHERE o.UserID = #UserID
AND NOT EXISTS (select * from [MyDB].[dbo].[PhoneNumber] z where z.ContactID = #ContactID);
-- -----------------------------------------------------
--MyDB.dbo.ContactOrg
-- -----------------------------------------------------
INSERT INTO [MyDB].[dbo].[Org]
(
ContactID,
OrgID
)
SELECT
#ContactID AS ContactID,
b.OrgID AS OrgID
FROM #T o WITH (NOLOCK)
INNER JOIN ImportQueue.dbo.OnviaAccountIDOrgIDMigrationLog b WITH (NOLOCK) ON o.AccountId = b.OnviaAccountID
WHERE o.UserID = #UserID
AND NOT EXISTS (select * from [MyDB].[dbo].[Org] z where z.ContactID = #ContactID);
-- -----------------------------------------------------
---- MyDB.dbo.UserIDContactIDMigrationLog
---- log output for new users
-- -----------------------------------------------------
INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
(
UserID,
ContactId,
CreatedDt,
UpdatedFlag
)
VALUES
(
#UserID,
#ContactID,
GETDATE(),
0
)
-- -----------------------------------------------------
-- EXISTING MATCHED USERS
-- -----------------------------------------------------
-- check if a contact is existing
IF (#ContactID IS NOT NULL)
BEGIN
-- -----------------------------------------------------
-- MyDB.dbo.Contact
-- -----------------------------------------------------
UPDATE MyDB.dbo.Contact
SET ContactFirstNameTx =
CASE
WHEN ContactFirstNameTx NOT IN ('', NULL) THEN c.FirstName
ELSE ContactFirstNameTx
END,
ContactLastNameTx =
CASE
WHEN ContactLastNameTx IN ('', NULL) THEN c.LastName
ELSE ContactLastNameTx
END,
ContactEmailTx =
CASE
WHEN ContactEmailTx IN ('', NULL) THEN c.Email
ELSE ContactEmailTx
END,
ContactTitleTx =
CASE
WHEN ContactTitleTx IN ('', NULL) THEN c.Title
ELSE ContactTitleTx
END,
[ContactCreateDt] =
CASE
WHEN ContactCreateDt IN ('', NULL) THEN c.UserCreatedDate
ELSE ContactCreateDt
END,
[ContactModifyByID] = #SysId,
[ContactModifyLoginTypeID] = - 10
FROM #T c
WHERE UserID = #UserID
AND ContactID = #ContactID;
-- -----------------------------------------------------
---- MyDB.dbo.UserIDContactIDMigrationLog
---- log output for existing matched users
-- -----------------------------------------------------
INSERT INTO MyDB.dbo.UserIDContactIDMigrationLog
(
UserID,
ContactId,
UpdatedDt,
UpdatedFlag
)
VALUES
(
#UserID,
#ContactID,
GETDATE(),
1
);
END
SET #I = #I+1;
END

Trigger did not run?

I have a trigger "after insert/update/delete/". It is supposed to count Balance on Account table based on transactions in Transaction table. It is on Transaction table. I am getting Balance discrepancies rarely, so have decided to add some logging into it. It dumps inserted+deleted tables (they are combined into a table var) and tsql statement which fired it. Judging from my log, it looks like the trigger did not fire for some inserts into Transaction table. Can this happen ? Are there any TSQL statement which change table data without firing trigger (except truncate table etc)?
Here is the trigger :
CREATE TRIGGER [dbo].[trg_AccountBalance]
ON [dbo].[tbl_GLTransaction]
AFTER INSERT, UPDATE, DELETE
AS
set nocount on
begin try
declare #OldOptions int = ##OPTIONS
set xact_abort off
declare #IsDebug bit = 1
declare #CurrentDateTime datetime = getutcdate()
declare #TriggerMessage varchar(max), #TriggerId int
if #IsDebug = 1
begin
select #TriggerId = isnull(max(TriggerId), 0) + 1
from uManageDBLogs.dbo.tbl_TriggerLog
declare #dbcc_INPUTBUFFER table(EventType nvarchar(30), Parameters Int, EventInfo nvarchar(4000) )
declare #my_spid varchar(20) = CAST(##SPID as varchar(20))
insert #dbcc_INPUTBUFFER
exec('DBCC INPUTBUFFER ('+#my_spid+')')
select #TriggerMessage = replace(EventInfo, '''', '''''') from #dbcc_INPUTBUFFER
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
declare #Oper int
select #Oper = 0
-- determine type of sql statement
if exists (select * from inserted) select #Oper = #Oper + 1
if exists (select * from deleted) select #Oper = #Oper + 2
if #IsDebug = 1
begin
select #TriggerMessage = '#Oper = ' + convert(varchar, #Oper)
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
if #Oper = 0 return -- No data changed
declare #TomorrowDate date = dateadd(day, 1, convert(date, getdate()))
declare #CurrentDate date = convert(date, getdate())
-- transactions from both inserted and deleted tables
declare #tbl_Trans table (FirmId int, GLAccountId int,
AmountDebit money, AmountCredit money, "Status" char(1), TableType char(1))
declare #tbl_AccountCounters table (FirmId int, GLAccountId int, Balance money)
declare #IsChange bit = null
insert into #tbl_Trans (FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", TableType)
select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'I'
from inserted
union
select FirmId, GLAccountId, AmountDebit, AmountCredit, "Status", 'D'
from deleted
if #IsDebug = 1
begin
select #TriggerMessage = (select * from #tbl_Trans for xml path ('tbl_Trans'))
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
insert into #tbl_AccountCounters (FirmId, GLAccountId, Balance)
select FirmId, GLAccountId, 0
from #tbl_Trans
group by FirmId, GLAccountId
if #Oper = 1 or #Oper = 2 -- insert/delete
begin
update #tbl_AccountCounters
set Balance = cnt.TransSum
from #tbl_AccountCounters as ac join
(
select trans.FirmId, trans.GLAccountId,
isnull(sum((trans.AmountDebit - trans.AmountCredit) * iif(trans.TableType = 'I', 1, -1)), 0) as TransSum
from #tbl_Trans as trans
where trans.Status = 'A'
group by trans.FirmId, trans.GLAccountId
) as cnt on ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId
select #IsChange = 1
end
else
begin
if update(AmountDebit) or update(AmountCredit) or update(Status) or update(GLAccountId)
begin
update #tbl_AccountCounters
set Balance = cnt.TransBalance
from #tbl_AccountCounters as ac join
(select trans.FirmId, trans.GLAccountId, isnull(sum(trans.AmountDebit - trans.AmountCredit), 0) as TransBalance
from dbo.tbl_GLTransaction as trans
where trans."Status" = 'A' and exists (select 1 from #tbl_AccountCounters as ac
where ac.GLAccountId = trans.GLAccountId and ac.FirmId = trans.FirmId)
group by trans.FirmId, trans.GLAccountId) as cnt on
ac.FirmId = cnt.FirmId and ac.GLAccountId = cnt.GLAccountId
select #IsChange = 0
end
end
if #IsDebug = 1
begin
select #TriggerMessage = '#IsChange = ' + isnull(convert(varchar, #IsChange), 'null')
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
select #TriggerMessage = (select * from #tbl_AccountCounters for xml path ('tbl_AccountCounters'))
insert into uManageDBLogs.dbo.tbl_TriggerLog (TriggerId, "Message", CreateDate)
values (#TriggerId, #TriggerMessage, #CurrentDateTime)
end
if #IsChange is not null
begin
update tbl_GLAccount
set tbl_GLAccount.Balance = iif(#IsChange = 1, cnt.Balance + acc.Balance, cnt.Balance),
tbl_GLAccount.LastUpdate = getutcdate(),
tbl_GLAccount.LastUpdatedBy = 1
from #tbl_AccountCounters as cnt join dbo.tbl_GLAccount as acc on
cnt.FirmId = acc.FirmId and cnt.GLAccountId = acc.GLAccountId
end
if (16384 & #OldOptions) = 16384 set xact_abort on
end try
begin catch
declare #ErrorLine varchar(max)
select #ErrorLine = uManageDb.dbo.udf_GetErrorInfo()
insert into uManageDb.dbo.tbl_TriggerError ("Name", "Message", CreateDate)
values ('AccountingDB..trg_AccountBalance', #ErrorLine, GETUTCDATE())
end catch
I think I've found it. I have this line:
select .. from inserted
union
select .. from deleted
and they inserted 5 trans for $300 and 4 trans $100. I've got 2 records (300 and 100) in my #tbl_Trans (it was in the log). That's probably was the bug. So log hellps and trigger run as it had to.
I'll replace union with union all.

SQL Server create Triggers on INSERT and SELECT OUTCOME

I try to create a Trigger that will insert a Unique ID in a table and then get the created ID and use it on the table that "Triggered the trigger"
So I insert some data in my table and then I want the trigger to insert some data in another table (master ID table), it then needs to get the just created ID (auto increment INT) and add this ID to the table ID that the trigger fired on.
I tried quite some different options but it just does not insert the ID and it will give me an error.
Hope you can help me out.
CREATE TRIGGER [dbo].[TROidMemoDiaryHeader]
ON [dbo].[InvoiceDiaryHeader]
FOR INSERT
AS
DECLARE #TEMP uniqueidentifier, #Lock INT, #Object INT, #User V ARCHAR(MAX), #Delay NCHAR(12), #ID INT
SET #TEMP = NEWID()
SET #Lock = '0' --staat geen wijziging meer toe
SET #Object = '5' -- aanduiding bron
SET #User = CURRENT_USER
--SET #Delay = '00:00:00:125' -- Wacht voor een kwart seconde voor verder te gaan
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
--SET NOCOUNT ON;
INSERT INTO [dbo].[AbstractMBOBase] ([Uid], [OptimisticLockField], [ObjectType], [User])
SELECT #TEMP, #Lock, #Object, #User
IF EXISTS (SELECT [Uid] FROM [dbo].AbstractMBOBase WHERE [Uid] = #TEMP)
BEGIN
INSERT INTO [InvoiceDiaryHeader](Oid)
SELECT Oid FROM inserted
/*
SELECT * INTO #tmpOID FROM AbstractMBOBase WHERE [Uid] = #TEMP
UPDATE [dbo].InvoiceDiaryHeader SET Oid = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
--CREATE TABLE [dbo].#TempOID()
--SELECT * INTO #TempOID FROM INSERTED
*/
/*
--UPDATE [MemoDiaryHeader]
SET #ID = (SELECT a.[Oid] FROM [dbo].[AbstractMBOBase] AS a
WHERE [Uid] = #TEMP)
INSERT INTO [MemoDiaryHeader]([Oid])
SELECT #ID
--FROM inserted
--select [Oid]=i.[Oid] from inserted i
*/
END
--END
END
GO

Trigger performance tuning

I'm running SQL Server 2008 R2 and I have a trigger that inserts into a table where asql agent job then kicks off every 10 sec's to run a sp to send an email notification. The problem that I'm running into is it appears that when a large number of inserts happen simultaneously the notifications can hang up and not get sent out for several minutes (sometimes as long as an hour) after the insert happens.The tb_BatchEmail only receives a few inserts (2-3) at a time, it's the Orders tables that can have several dozen inserts happen at once. So my question is - Is this the best way to setup this type of trigger or is there a better way that is more efficient and won't lag behind when loads of table inserts happen at once?
Here is the trigger:
ALTER TRIGGER [dbo].[VoceraOeOrders] ON [dbo].[Orders]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.tb_BatchEmail (
BatchEmailID
,[To]
,Body
,[Subject]
,[Profile]
,OrderID
,OrderDateTime
,SentDateTime
)
SELECT '0'
,'some_email'
,CASE
WHEN RoomTreatmentID IS NULL
THEN 'No Room#'
ELSE RoomTreatmentID
END + '-' + OrderedProcedureName
,CASE
WHEN Category = 'US'
THEN 'Stat Ultra Sound'
WHEN Category = 'NUC'
THEN 'Stat Nuclear'
WHEN Category = 'ECHO'
THEN 'Stat Echo'
WHEN Category = 'CT'
THEN 'Stat C T'
WHEN Category = 'MRI'
THEN 'Stat M R I'
WHEN Category = 'XRAY'
THEN 'Stat Xray'
ELSE 'Stat Order Alerts'
END
,'Alert'
,OrderID
,OrderDateTime
,NULL
FROM inserted i
INNER JOIN dbo.Patients pat
ON pat.VisitID = i.VisitID
AND pat.SourceID = i.SourceID
WHERE Priority = 'STAT'
AND Category IN ('CT', 'MRI', 'XRAY', 'US', 'NUC', 'ECHO')
AND CurrentLocationID = 'ED'
END
And here is the sp that is set to kick off every 10 seconds via server agent job:
ALTER PROCEDURE [dbo].[sp_SendVoceraMail]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Id INT
DECLARE #To VARCHAR(250)
DECLARE #Body VARCHAR(250)
DECLARE #Subject VARCHAR(50)
DECLARE #ProfileName VARCHAR(20)
WHILE (
SELECT count(*)
FROM tb_BatchEmail
WHERE BatchEmailID = 0
) > 0
BEGIN
SELECT TOP 1 #Id = Id
,#To = [To]
,#Body = Body
,#Subject = [Subject]
,#ProfileName = [Profile]
FROM tb_BatchEmail
WHERE BatchEmailID = 0
EXEC msdb.dbo.sp_send_dbmail #recipients = #To
,#body = #Body
,#subject = #Subject
,#profile_name = #ProfileName
UPDATE tb_BatchEmail
SET BatchEmailID = 1
,SentDateTime = GETDATE()
WHERE Id = #Id
END
END

Resources