Execute a Stored Procedure with parameters from a SELECT - sql

I have an SP which needs to be executed as many times as i find rows in a temporary table (Just like insertion using a select statement)
My table #OutMessageQIDs has id column (with say 10 rows)
The SP HL7_InsertComponentLog requires 5 parameters as following
EXEC [HL7_InsertComponentLog] --#iPraID,#iComponentID,#vComponentType,'Send',id
SELECT #iPrcID,#iComponentID,#vComponentType,'Send',id
FROM #OutMessageQIDs
Can i do it without using Cursor or Loop kind of thing?
EDIT 1: a little more explanation - #OutMessageQIDs is a temporary table storing the ids of items Queued in a QueueTable (in an SP). and the SP HL7_InsertComponentLog logs the Queue-ed items. Depending upon #vComponentType, it logs different type of data.
EDIT 2: SP is as :
Create Procedure [dbo].[HL7_InsertComponentLog]
#IPracID [int],
#iComponentID [bigint],
#vComponentType varchar(50),
#vStatus varchar(200),
#iOutMessageQueueID [bigint]
AS
select* from hl7_outmessagelog
IF #vStatus != 'Success'
BEGIN
SELECT -1
END
ELSE IF #vComponentType = 'LabOrder' OR #vComponentType = 'ProcedureOrder' OR #vComponentType = 'RadiologyOrder'
BEGIN
SELECT -1
END
ELSE IF #vComponentType = 'LabResult' OR #vComponentType = 'ProcedureResult'
BEGIN
INSERT INTO OrderResult_Addendum (iOrderDetailID,IUserID,DateTime_Stamp,iType,VchComments,iOrderID,iPracID,vAction,bAcknowledge)
SELECT NULL,0,dTimeStamp,NULL,NULL,#iComponentID,#iPracID,#vStatus,0
FROM HL7_OutMessageQueue Q
WHERE Q.iOutQueueID = #iOutMessageQueueID and iPracID = #iPracID
END
ELSE IF #vComponentType = 'RadiologyResult'
BEGIN
INSERT INTO OrderResult_Addendum (iOrderDetailID,IUserID,DateTime_Stamp,iType,VchComments,iOrderID,iPracID,vAction,bAcknowledge)
SELECT iOrderDetailID,0,Q.dTimeStamp,NULL,NULL,#iComponentID,#iPracID,#vStatus ,0
FROM HL7_OutMessageQueue Q
INNER JOIN OrderResultDetails det ON Q.iComponentID = det.iOrderID
WHERE Q.iOutQueueID = #iOutMessageQueueID and Q.iPracID = #iPracID
END
ELSE IF #vComponentType = 'ClinicalNotes'
BEGIN
INSERT INTO Note_provider_encounter(iReportID,iUserID,iComponentID,dEncounterDate,vaction)
SELECT #iComponentID,0,0,dTimeStamp,#vStatus
FROM HL7_OutMessageLog Where iOutMessageLogID = #iOutMessageQueueID and iPracID = #iPracID
END
ELSE IF #vComponentType = 'PatientDemo'
BEGIN
DECLARE #IPatID int
DECLARE #IUserID int
SELECT #IPatID = iPatID,#IUserID = iUserID
FROM HL7_OutMessageQueue Q
WHERE Q.iOutQueueID = #iOutMessageQueueID and iPracID = #iPracID
EXEC [dbo].[InsertPatientLog] #IPracID,#IPatID,#vStatus,#IUserID
END

No you can't EXEC a stored procedure for each row in a table without using a loop of some kind.
What does your stored procedure do? It may be possible to extract the logic from that and perform it in a set based manner against the whole table.
e.g. Just use
INSERT INTO ComponentLog
SELECT #iPrcID,#iComponentID,#vComponentType,'Send',id
FROM #OutMessageQIDs
instead of calling the stored procedure for each row.

Related

Stored procedure not inserting data into table

I'm trying to implement a stored procedure like this where it's going to compare UserID from another table. If that user id already exists in dbo.user info table, it will insert data into [dbo].[BulkUploadTagDetail] table.
Every time I execute this stored procedure running into an issue that the data doesn't get inserted into my database table.
CREATE PROCEDURE [dbo].[InsertBulkUploadTagDetail]
(#BulkTagID INT,
#PortalUserID UNIQUEIDENTIFIER,
#EmailAddress VARCHAR(256),
#BulkUploadFileName VARCHAR(256),
#CreatedOn DATETIME2(7),
#IsCompleted BIT = 0)
AS
BEGIN
SET NOCOUNT ON
IF EXISTS (SELECT UserID
FROM dbo.UserInfo
WHERE UserID = #PortalUserID)
BEGIN
UPDATE [unp]
SET [unp].[BulkTagID] = #BulkTagID,
[unp].[UserID] = #PortalUserID,
[unp].[EmailAddress] = #EmailAddress,
[unp].[BulkUploadFileName] = #BulkUploadFileName,
[unp].[CreatedOn] = GETUTCDATE(),
[unp].[IsCompleted] = #IsCompleted
FROM
[dbo].[InsertBulkUploadTagDetail] unp
INNER JOIN
[dbo].[UserInfo] uinfo ON [unp].[UserID] = [uinfo].[UserID]
WHERE
[unp].[UserID] = #PortalUserID
END
ELSE
BEGIN
INSERT INTO [dbo].[BulkUploadTagDetail]
([BulkTagID], [PortalUserID], [EmailAddress],
[BulkUploadFileName], [CreatedOn], [IsCompleted])
VALUES (#BulkTagID, #PortalUserID, #EmailAddress,
#BulkUploadFileName, #CreatedOn, #IsCompleted)
END
END

Set Value From Action Update, Delete, Inserted in Stored Procedure SQL

I have created my stored procedure, but I am confused how to set one column of from my table.
This is separate of my code:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
AS
BEGIN
DECLARE #action NVARCHAR(10),
#insCount INT = (SELECT COUNT (*) FROM INSERTED),
#delCount INT = (SELECT COUNT (*) FROM DELETED)
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL], -- I want to set this value as 1(if there is a new input data, 2
-- (if there is updated data), 3 (if there is deleted data) from
-- from another field
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT
END
How do I set column ID_OPERASIONAL as 1 (if there is a new data from another field), 2 for exists updated data from another field, 3 for deleted data from another field in a stored procedure.
ERROR from this code is:
Invalid object name 'INSERTED'
The problem the ERROR shows is that you cannot use deleted/inserted tables in stored procedures but just accessible in triggers.
If you want to have the count of inserted records or deleted records in a table there are two ways for doing this which the easiest one is:
Create you stored procedure like this:
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE,#DeletedCount INT , #InsertedCount Int
AS
BEGIN
...
Create a Trigger after insert and delete (so you can have inserted/deleted tables)
Then get the count just like you did in your code:
DECLARE #action nvarchar (10),
#insCount int = (SELECT COUNT (*) FROM INSERTED),
#delCount int = (SELECT COUNT (*) FROM DELETED)
Call your stored procedure in the Trigger and pass the #insCount and #delCount as inputs
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE() , #InsertedCount = #insCount , #DeletedCount = #delCount
A similar question is this for more other ways like temp tables or...
How use inserted\deleted table in stored procedure?
Also the link below is a question asking defining a trigger for both delete and insert so you can use both deleted/inserted tables together
SQL Trigger on Update, Insert, Delete on non-specific row, column, or table
Second way which is better when you are doing all these process a lot, is to get the log of your inserts or updates or deletes so you dont use triggers which reduce performance of your process.
(If usefull I can recommend some ideas for saving table logs)
CREATE PROC [dbo].[SP_Gabungan]
#REPORT_DT DATE
,#DeletedCount INT
,#InsertedCount INT
,#UpdateCount INT
AS BEGIN
DECLARE #action INT
SET #action = CASE
WHEN #InsertCount <> 0 THEN 1
WHEN #UpdateCount <> 0 THEN 2
WHEN #DeletedCount <> 0 THEN 3
END
SELECT
#REPORT_DT AS REPORT_DATE,
FD.BRANCH_CODE AS [BRANCH],
#action AS [ID_OPERATIONAL],
BR.REGULATOR_BRANCH as [RG_BRANCH]
FROM
[DBO].[F_RR_FUNN] FD
LEFT JOIN
[DBO].[MS_BRANCH] BR ON BR.BRANCH_CD = FD.BRANCH_CODE
WHERE
FD.GROUP_PRODUCT = 'CA'
AND Y17sa = '1'
AND FD.REPORT_DATE = #REPORT_DT END
CREATE TRIGGER [YourTriggerName]
AFTER INSERT/UPDATE/DELETE ON [db].[tablename]
FOR EACH ROW
BEGIN
DECLARE
#insCount int = (SELECT COUNT (*) FROM New), -- New in MySQL is same as inserted,deleted,updated
#delCount int = (SELECT COUNT (*) FROM Old),
#upCount int = (SELECT COUNT (*) FROM New),
EXEC [dbo].[SP_Gabungan]
#REPORT_DT = GETDATE()
,#DeletedCount = #delCount
,#InsertedCount = #insCount
,#UpdateCount = #upCount
END

Stored Procedure to check the existence of email in tables

I am new to SQL stored procedures. I need to write a SQL to check a email exists in multiple tables. If a email contains in First Table it returns true and should not execute the rest. Like wise if not I need to check the second table and if i found return true. Finally if i found in last Table I need to return true and else i need to return false.
I am stuck in achieving this. I tried like this. Gives me syntax errors. Please share me a solution for this.
USE Users_UserDetials;
GO
CREATE PROCEDURE Users.GetUserPermissions
#userEmail nvarchar(50),
#areaId nvarchar(10),
#villageCode nvarchar(10)
AS
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM Users.GlobalUsers AS GU
WHERE GU.UserEmail = #userEmail)
ELSE
IF EXISTS (SELECT 1 FROM Users.AreaSpecificUsers AS AU
WHERE AU.UserEmail = #userEmail)
ELSE
IF EXISTS (SELECT 1 FROM Users.VillageSpecificUsers AS VU
WHERE VU.UserEmail = #userEmail)
ELSE
'0'
GO
USE Users_UserDetials;
GO
CREATE PROCEDURE Users.GetUserPermissions
#userEmail nvarchar(50),
#areaId nvarchar(10),
#villageCode nvarchar(10)
AS
SET NOCOUNT ON;
IF EXISTS (SELECT 1 FROM Users.GlobalUsers AS GU
WHERE GU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
IF EXISTS (SELECT 1 FROM Users.AreaSpecificUsers AS AU
WHERE AU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
IF EXISTS (SELECT 1 FROM Users.VillageSpecificUsers AS VU
WHERE VU.UserEmail = #userEmail)
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 0
END
END

SQL Table Valued Function in Select Statement

SQL is not my best thing but I have been trying to optimize this stored procedure. It had multiple scalar-valued functions that I tried to change to table-valued functions because I read in many places that it's a more efficient way of doing it. And now I have them made but not real sure how to implement or if I maybe just didn't create them correctly.
This is the function I'm calling.
Alter FUNCTION [IsNotSenateActivityTableValue]
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
returns #T table(result varchar(max))
as
begin
DECLARE #result varchar(max);
declare #countcodes int;
declare #ishousebill int;
select #ishousebill = count(billid)
from BillMaster
where BillID = #BillID and Chamber = 'H'
If (#ishousebill = 0)
begin
SELECT #countcodes = count([ActivityCode])
FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%' and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
if (#countcodes = 0)
begin
set #result = 'test'
end
else
begin
set #result = 'test2'
end
end
else
begin
set #result = #TextToDisplay
end
RETURN
END
And this is how I was trying to call them like this. I would prefer just being able to put them in the top but really anything that works would be good.
SELECT distinct
ActionDates.result as ActionDate
,ActivityDescriptions.result as ActivityDescription
FROM BillWebReporting.vwBillDetailWithSubjectIndex as vw
left outer join [BillWebReporting].[HasHouseSummary] as HasSummary on vw.BillID = HasSummary.BillID
outer APPLY dbo.IsNotSenateActivityDateTableValue(ActivityCode,vw.BillID,[ActionDate]) ActionDates
OUTER APPLY dbo.IsNotSenateActivityTableValue(ActivityCode,vw.BillID,[ActivityDescription]) as ActivityDescriptions
Getting a count just to see if at least one row exists is very expensive. You should use EXISTS instead, which can potentially short circuit without materializing the entire count.
Here is a more efficient way using an inline table-valued function instead of a multi-statement table-valued function.
ALTER FUNCTION dbo.[IsNotSenateActivityTableValue] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN (SELECT result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END);
GO
Of course it could also just be a scalar UDF...
ALTER FUNCTION dbo.[IsNotSenateActivityScalar] -- always use schema prefix!
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #result VARCHAR(MAX);
SELECT #result = CASE WHEN EXISTS
(SELECT 1 FROM dbo.BillMaster
WHERE BillID = #BillID AND Chamber = 'H'
) THEN #TextToDisplay ELSE CASE WHEN EXISTS
(SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode]
where ActivityDescription not like '%(H)%'
and ActivityType = 'S'
and [ActivityCode] = #ActivityCode
) THEN 'test2' ELSE 'test' END
END;
RETURN (#result);
END
GO
Table-valued functions return a table, in which, like any other table, rows have to be inserted.
Instead of doing set #result = ....., do:
INSERT INTO #T (result) VALUES ( ..... )
EDIT: As a side note, I don't really understand the reason for this function to be table-valued. You are essentially returning one value.
First of all UDFs generally are very non-performant. I am not sure about MySQL, but in Sql Server a UDF is recompiled every time (FOR EACH ROW OF OUTPUT) it is executed, except for what are called inline UDFs, which only have a single select statement, which is folded into the SQL of the outer query it is included in... and so is only compiled once.
MySQL does have inline table-valued functions, use it instead... in SQL Server, the syntax would be:
CREATE FUNCTION IsNotSenateActivityTableValue
(
#ActivityCode int,
#BillId int,
#TextToDisplay varchar(max)
)
RETURNS TABLE
AS
RETURN
(
Select case
When y.bilCnt + z.actCnt = 0 Then 'test'
when y.bilCnt = 0 then 'test2'
else #TextToDisplay end result
From (Select Count(billId) bilCnt
From BillMaster
Where BillID = #BillID
And Chamber = 'H') y
Full Join
(Select count([ActivityCode]) actCnt
From [HouseCoreData].[dbo].[ActivityCode]
Where ActivityDescription not like '%(H)%'
And ActivityType = 'S'
And [ActivityCode] = #ActivityCode) z
)
GO

Optimizing the stored procedure to process 3 million records

I have designed a stored procedure usign Sql Server 2005 below to compare 3 million records in each of the Profile and Source Table, and update the Source table with records exist in another table (PROFILE_BC) which will also have about 3 million records.
I am trying to Optimize this code below. Can you suggest any other method ? I just worried that this will take more than about 6 hours to complete. Can we do the same using DTS ? And ideas how this can be done using DTS. Some suggested that there is a component called, Lookup, Fuzzy Lookup that can be used. Any ideas in optimizing the same are welcome.
USE Database
GO
/****** Object: StoredProcedure [dbo].[ProcName] Script Date: 11/13/2010 17:15:04 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[ProcName]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #not_on_ebc_file_xx## char(2);
SET #not_on_ebc_file_xx## = 35;
DECLARE #voters_no varchar(18);
DECLARE #candidate_id char(10);
DECLARE #perm_disq_temp char(2);
DECLARE #voters_no_jms varchar(18);
DECLARE PROFILES_CURSOR CURSOR LOCAL FAST_FORWARD
FOR SELECT CP.CANDIDATE_ID, CP.VOTERS_NO FROM PROFILE CP INNER JOIN SOURCE SR ON
CP.CANDIDATE_ID = SR.CANDIDATE_ID
WHERE CP.CANDIDATE_ID NOT LIKE 'MA%';
OPEN PROFILES_CURSOR;
FETCH NEXT FROM PROFILES_CURSOR
INTO #candidate_id, #voters_no;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #voters_no_jms = VOTERS_NO FROM PROFILE_BC WHERE VOTERS_NO = #voters_no;
SELECT #perm_disq_temp = PERM_DISQ FROM SOURCE WHERE CANDIDATE_ID = #candidate_id;
IF (#voters_no_jms = #voters_no) -- record exists in jms_temp table/ebc file
BEGIN
IF (#perm_disq_temp = #not_on_ebc_file_xx##)
BEGIN
UPDATE SOURCE SET PERM_DISQ = '' WHERE CANDIDATE_ID = #candidate_id;
END
END
ELSE
BEGIN
IF (#perm_disq_temp = '' OR #perm_disq_temp IS NULL)
BEGIN
UPDATE SOURCE SET PERM_DISQ = #not_on_ebc_file_xx## WHERE CANDIDATE_ID = #candidate_id;
END
END
SET #voters_no_jms = '';
FETCH NEXT FROM PROFILES_CURSOR INTO #candidate_id, #voters_no;
END
CLOSE PROFILES_CURSOR;
DEALLOCATE PROFILES_CURSOR;
END
you should always try to avoid using cursors if you have performance on mind.
Instead of using a cursor you could do this. Try to think in terms of sets when dealing with SQL. I commented out the update part of the query and added a select so that you can see the data.
BEGIN TRANSACTION
DECLARE #not_on_ebc_file_xx## char(2);
SET #not_on_ebc_file_xx## = 35;
--UPDATE SR
--SET PERM_DISQ =
-- CASE WHEN NOT PROFILE_BC.VOTERS_NO IS NULL THEN
-- CASE WHEN PERM_DISQ.PERM_DISQ = #not_on_ebc_file_xx## THEN ''
-- ELSE PERM_DISQ.PERM_DISQ
-- END
-- WHEN PERM_DISQ.PERM_DISQ = '' OR PERM_DISQ IS NULL THEN #not_on_ebc_file_xx##
-- ELSE PERM_DISQ.PERM_DISQ
-- END
SELECT CASE WHEN NOT PROFILE_BC.VOTERS_NO IS NULL THEN
CASE WHEN PERM_DISQ.PERM_DISQ = #not_on_ebc_file_xx## THEN ''
ELSE PERM_DISQ.PERM_DISQ
END
WHEN PERM_DISQ.PERM_DISQ = '' OR PERM_DISQ IS NULL THEN #not_on_ebc_file_xx##
ELSE PERM_DISQ.PERM_DISQ
END AS PERM_DISQ
FROM PROFILE CP
INNER JOIN SOURCE SR
ON CP.CANDIDATE_ID = SR.CANDID_ID
LEFT JOIN PROFILE_BC
ON CP.VOTERS_NO = PROFILE_BC.VOTERS_NO
LEFT JOIN SOURCE PERM_DISQ
ON CP.CANDIDATE_ID = PERM_DISQ.CANDIDATE_ID
WHERE CP.CANDIDATE_ID NOT LIKE 'MA%';
ROLLBACK TRANSACTION;
uncomment the update and set statement and comment out the select statement to update