I am trying to execute an email that contains the results of a stored procedure. I was looking at other posts in stackoverflow but cannot seem to get past an error that states "Msg 2714, Level 16, State 1, Procedure CompareConfirm_FraudRules, Line 38
There is already an object named '##returnInactiveRules' in the database." I've looked in the DB and there is no object that exists with this name already. Any suggestions on how to fix this issue would be appreciated. Thanks.
Here is the my SP:
BEGIN
CREATE TABLE ##returnInactiveRules (
ProductName varchar(100),
ChannelName varchar(100),
StrategyCode varchar(100),
StrategyName varchar(100),
RuleCode varchar(100),
RuleName varchar(100),
On_Off varchar(5)
);
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
-- SELECT R.RuleCode, R.Name as RuleName, S.StrategyCode, S.Name as StrategyName, R.IsActive
SELECT DISTINCT
CASE
WHEN PC.ProductIdentifier='2000' THEN 'GP'
WHEN PC.ProductIdentifier='1000' THEN 'MB'
END as ProductName, C.Name as ChannelName, S.StrategyCode, S.Name as StrategyName, R.RuleCode, R.Name as RuleName,
CASE
WHEN R.IsActive = 1 THEN 'On'
WHEN R.IsActive = 0 THEN 'Off'
END as On_Off
INTO ##returnInactiveRules
FROM dbo.[Rule] R
INNER JOIN dbo.Strategy S
on S.KnockoutRuleSet = R.KnockoutRuleSet
INNER JOIN dbo.RFAI P
on R.RFAIId = P.RFAIId
INNER JOIN dbo.DecisionStatus D
on D. StatusId = R. StatusId
LEFT OUTER JOIN dbo.NOAA N
on N.NOAAId = R.NOAAId
INNER JOIN dbo.RuleQuestionsXRef Q
ON Q.RuleId = R.RuleId
INNER JOIN ProductChannelStrategyRuleXref X
ON X.RuleId = R.RuleId
INNER JOIN ProductChannelStrategy CS
ON CS.ProductChannelStrategyId = X.ProductChannelStrategyId
INNER JOIN ProductChannel PC
ON PC.ProductChannelId = CS.ProductChannelId
INNER JOIN dbo.Channel C
ON C.ChannelId = PC.ChannelId
WHERE R.IsActive = 0
AND R.RuleCode IN ('F06',
'F07',
'F11',
'F12',
'F14',
'F15',
'F16',
'F17',
'F19',
'F23',
'F25',
'F26',
'F10'
)
-- ORDER BY R.RuleCode, R.Name;
ORDER BY ProductName, C.Name, S.StrategyCode, S.Name, R.RuleCode, R.Name;
-- SELECT * FROM #returnValue;
-- Email the results in the #returnValue table --
EXEC msdb.dbo.sp_send_dbmail
#execute_query_database='Prod-XXX',
#recipients=N'msavoy#xxx.com',
#body='Attached please find a file with the results.',
#subject ='Compare Fraud Rule Results',
#profile_name ='Reports',
#query ='EXEC CompareConfirm_Rules',
#attach_query_result_as_file = 1,
#query_attachment_filename ='CompareRuleResults.txt'
END
DROP TABLE ##returnInactiveRules;
GO
If exists Drop it, then create the table
IF Object_id('tempdb..##returnInactiveRules') IS NOT NULL
DROP TABLE ##returnInactiveRules
CREATE TABLE ##returnInactiveRules
(
ProductName VARCHAR(100),
ChannelName VARCHAR(100),
StrategyCode VARCHAR(100),
StrategyName VARCHAR(100),
RuleCode VARCHAR(100),
RuleName VARCHAR(100),
On_Off VARCHAR(5)
);
Temp tables which start with ## are global temp tables, so if you have 2 connection opened, and one of them created a table called ##Temp, you would not be able to create the same table from connection 2, until it is dropped by any of the 2 connections.
Best thing would be to use #returnInactiveRules and check for existence before creating it.
IF OBJECT_ID('tempdb..#returnInactiveRules') IS NOT NULL
DROP TABLE #returnInactiveRules
GO
Have the drop statement at the beginning and if it's a global temp table ensure that only one process is creating it at any one time as two cannot exist simultaneously..
Also, unless you require other sessions to access the data, consider using a temp table rather than a global temp table by replacing the ## with #
Related
Being a super novice at this, I would like some guidance on this, please.
I need to compare two sets of data and update one set with a value. This is what I have so far.
PROCEDURE [dbo].[update_personnel_rank]
AS
DECLARE #frsid VARCHAR
DECLARE #officerid VARCHAR
DECLARE #hrrank VARCHAR
DECLARE #personnelrank VARCHAR
DECLARE #farank VARCHAR
DECLARE #rank VARCHAR(150)
SET #rank = 'Admin Spec II'
BEGIN
SET NOCOUNT ON;
SELECT
#frsid = hr.FRSID,
#officerid = p.OfficerID,
#hrrank = hr.Rank,
#personnelrank = p.Rank,
#farank = r.FA_Rank
FROM
[FireApp_REPL_DW_Data].[dbo].[MCFRSCombinedPersonnelandPimsStaff] hr
INNER JOIN
[fh_reports].[dbo].[personnel_bk] p ON p.OfficerID = hr.FRSID
INNER JOIN
[fh_reports].[dbo].[Rank_Lookup_tbl] r ON r.FA_Rank = hr.Rank
WHERE
(p.rank <> hr.Rank OR p.rank = '')
AND p.Rank = #rank
UPDATE [fh_reports].[dbo].[personnel_bk]
SET Rank = #farank
WHERE OfficerID = #officerid
END
GO
The select query returns 3 records and this stored procedure runs without any error, but it does not update the records. Since the select query returns 3 records, I think I need to change the parameter setting accordingly, but not sure how...
To #Sami's point, if you are not returning those variables, you do not need to set them and can instead just run the update:
USE [YourDatabase]
GO
SET NOCOUNT ON
GO
ALTER PROCEDURE [dbo].[update_personnel_rank]
#rank VARCHAR(150) --= 'Admin Spec II'
AS
BEGIN
IF #rank IS NULL OR #rank = ''
RAISERROR('Please enter a valid rank string.', 16, 1)
UPDATE hr
SET [Rank] = r.FA_Rank
FROM [FireApp_REPL_DW_Data].[dbo].[MCFRSCombinedPersonnelandPimsStaff] [hr]
INNER JOIN [fh_reports].[dbo].[personnel_bk] [p]
ON [p].[OfficerID] = [hr].[FRSID]
INNER JOIN [fh_reports].[dbo].[Rank_Lookup_tbl] [r]
ON [r].[FA_Rank] = [hr].[Rank]
WHERE [p].[rank] <> [hr].[Rank]
AND ([p].[Rank] = #rank OR p.[Rank] = '')
END ;
GO
This question already has answers here:
SQL Server Insert if not exists
(13 answers)
Closed 3 years ago.
I want to write a stored procedure to insert data into a table and also to check whether same data already exist?
If yes, then exception throw as already exist. But I don't know where should I add an exception. Please help.
ALTER PROCEDURE [dbo].[datakutipantest1]
AS
BEGIN
DECLARE #ModifiedDate datetime = GETDATE()
INSERT INTO spk_DataKutipan ([NO_BIL], [NO_AKAUN], [TKH_BAYAR],
[STESYEN], [AMAUN_BAYAR], [JENIS_BAYAR], [NO_RESIT], [STATUS], [NO_VOT], [TKH_MODIFIKASI])
SELECT
D.BillNo,
D.AccountNo,
D.TxDate,
D.ReferenceCode,
D.Amount,
PaymentTypeId,
D.ReferenceNo,
D.Status,
D.RevenueCode,
#ModifiedDate
FROM
(SELECT
B.ComponentId,
B.AccountNo,
B.BillNo,
B.RevenueCode,
B.Amount,
B.TxId,
ReferenceNo,
B.ReferenceCode,
status,
TxDate
FROM
(SELECT
A.ComponentId,
A.TxId,
AccountNo,
BillNo,
RevenueCode,
Amount,
C.ReferenceCode
FROM
rcs_TxBillItem A
INNER JOIN
(SELECT
ComponentId,
ComponentName,
ReferenceCode
FROM
rcs_Component
WHERE
IsDeleted = 0) C ON C.ComponentId = A.ComponentId) B
INNER JOIN
rcs_TxBill P ON P.TxId = B.TxId) D
INNER JOIN
rcs_TxBillPayment E ON E.TxId = D.TxId
END
GO
CREATE PROCEDURE [dbo].[Useradd]
#username varchar(20),
#pword nvarchar(20),
#empname varchar(20),
#email nvarchar(50),
#designation varchar(20),
#reportto varchar(20) AS
IF (SELECT COUNT(*) FROM Users WHERE username= #username) < 1
BEGIN
INSERT INTO Users(username,pword,empname,email,designation,reportto)
VALUES(#username,#pword,#empname,#email,#designation,#reportto)
END
Consider to use MERGE
MERGE <target_table> [AS TARGET]
USING <table_source> [AS SOURCE]
ON <search_condition> --For example ColumnSource = ColumnTable
WHEN MATCHED --Rows already exist
THEN UPDATE target_table SET ... --Do Update for example
WHEN NOT MATCHED BY TARGET --Rows not exist on Target Table
THEN INSERT(...) VALUES(...) --Do Insert for example
WHEN NOT MATCHED BY SOURCE --Rows not exist on Source table but exists on Target Table
THEN DELETE ... --Do Delete for example
The MERGE statement basically merges data from a source result set to a target table based on a condition that you specify and if the data from the source already exists in the target or not. The new SQL command combines the sequence of conditional INSERT, UPDATE and DELETE commands in a single atomic statement, depending on the existence of a record.
The reason of creating a stored procedure is to schedule a job to send a biweekly report to our staff (coordinators) using SQL Server db mail.
I'm having problems with getting it to work the right way. I don't usually work with cursors but couldn't find other choices.
Here's the issue. I tested the query by set criteria to send only to one Coordinator with one record "if #Coord_Email = 'lamez.sw1#gmail.com', where n.id = '43422546'". However the query been running over 5 minutes so i had to cancel it.
ALTER PROCEDURE [dbo].[sp_MZ_Coord_rpt_s9]
AS
BEGIN
DECLARE #Member_ID VARCHAR(20)
DECLARE Report_S9 CURSOR FOR
SELECT id
FROM name
WHERE status = 'a'
OPEN Report_S9
FETCH NEXT FROM Report_S9 INTO #member_ID
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Coord_ID Varchar(20)
DECLARE #CO_ID Varchar(20)
DECLARE #Coord_Name Varchar(50)
DECLARE #Coord_Email Varchar(50)
SELECT #CO_ID = ID
FROM Relationship
WHERE id = #Member_ID
SELECT #Coord_ID = target_id
FROM Relationship
WHERE RELATION_TYPE = 'CO'
SELECT #Coord_Name = FULL_NAME
FROM Name
WHERE ID = #Coord_ID
SELECT #Coord_Email = email
FROM Name
WHERE id = #Coord_ID
IF #Coord_Email <> ''
BEGIN
SELECT
n.id, n.CO_ID, n.FULL_NAME, a.TRANSACTION_DATE, a.UF_1, r.TARGET_ID
FROM name n
INNER JOIN activity a ON n.id = a.id
INNER JOIN Tops_Profile tp ON a.id = tp.ID
INNER JOIN Relationship r ON n.CO_ID = r.ID
WHERE
n.id = #member
AND UF_1 <> ''
AND (DATEDIFF(dd, TRANSACTION_DATE, GETDATE()) < 2)
AND r.RELATION_TYPE = 'co'
ORDER BY
TRANSACTION_DATE
EXEC msdb..sp_send_dbmail
#profile_name = 'TOPS.ADMIN',
#recipients = #Coord_Email,
--#blind_copy_recipients = ,
#subject = 'S9 Report'
End
FETCH NEXT FROM Report_S9 INTO #member_ID
END
CLOSE Report_S9
DEALLOCAT Report_S9
End
Any help is greatly appreciated.
The FETCH NEXT should be outside of your check for null. You need to continue the loop, even when there is nothing to do.
I am new to MS SQL 2014 stored procedure. I have a table as shown below. I want to create a stored procedure.
I design my stored procedure but I feel so difficult that I can’t even start. Can anyone help me how can I do that?
I have to send CardNo, CardPassword and the PosSerialNo to SQL store procedure. In return I need to get customer name, surname and the amount.
SENDING: CardNo, CardPass, PosSerialNo
RECEVING:
If Sending.CardPass = CardPasswordTable.Password
Do the following:
If successful I get: CustomerName, CustomerSurname and Amount
If not I get: “No Data Found”
MY TABLES:
1) CardIssueTable:
Columns:
CardId, CardNo, CustId
2) CustomerTable:
Columns:
CustId, CustName, CustSurname
3) PosTable:
Columns:
PosId, PosSerial, PosLocation
4) PaymentTable:
Columns:
PaymentId, PaymentLoaction, PaymentAmount
5) CardPasswordTable:
Columns:
PassId, Password
Edited:
Here is my Stored Procedure. When I execute I get an error.
Store Procedure:
USE [LTKB_Card]
GO
/****** Object: StoredProcedure [dbo].[CardCustomerControl] Script Date: 2.03.2016 10:03:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*parameters*/
ALTER Procedure [dbo].[CardCustomerControl](
#CardNo varchar(50),
#CardPass varchar(10),
#PosSerialNo varchar(50)
)
AS
BEGIN
DECLARE /*internal of sp*/
#CustName varchar(100),
#CustId int,
#CustSurName varchar(100),
#Amout int,
#PosId int,
#PassId int
SELECT #CustName=CUS.CustomerName, #CustSurName=CUS.CustomerSurname ,#CustId=C.CardCustomer
FROM CardBASIM C
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CustomerName
WHERE C.CardNo=#cardNo
SELECT #PassId=PASID FROM CardPASSLIST C WHERE C.CardPassowrd=#CardPass
SELECT #Amout=PT.PaymentAmount
FROM POS P
INNER JOIN PAYMENT PT on P.PosLocation=PT.PAYID
WHERE P.PosSerial=#PosSerialNo
if (#CustId is not null and #PassId is not null and #PosId is not null)
begin
select #CustName CustName, #CustSurName CustSurname , #Amout Amount
end
else
begin
select 'NoDataFound'
end
END
Execute Statement:
USE [LTKB_Card]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[CardCustomerControl]
#CardNo = N'5852354822730001',
#CardPass = N'jSCm6xkBpK',
#PosSerialNo = N'RR-312-001387'
SELECT 'Return Value' = #return_value
GO
Error:
Msg 248, Level 16, State 1, Procedure ElitcardCustomerControl, Line 21
The conversion of the varchar value '5852354822730001' overflowed an
int column.
(1 row(s) affected)
(1 row(s) affected)
And here are the relationship of the tables:
Looking at the data model this line
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CustomerName
Is joining a string to an integer. I can't look at the data to see if this is the exact problem but according to your model the join you want is this:
INNER JOIN CUSTOMERS CUS ON C.CardCustomer=CUS.CUSTID
This is a standard relationship -- I've no idea why you felt the Customer's name was the field to join to.
I truly hope you do not store password in plain text, and I don't get all relations between your tables (for example where is relation between postable and paymenttable, between passwordtable and cartable), but I give you an example of SP you needed. Don't forget IT'S JUST EXAMPLE.
CREATE PROCEDURE dbo.spnamegoeshere
#CardNo int,
#CardPass nvarchar(8),
#PosSerialNo nvarchar(8)
AS
BEGIN
--Check if password is Sending.CardPass = CardPasswordTable.Password
IF (SELECT ISNULL(PassId,0) FROM CardPasswordTable WHERE Password = #CardPass) != 0
BEGIN
-- If successful you get: CustomerName,
-- CustomerSurname and Amount
-- not sure of table relations
SELECT ct.CustomerName, ct.CustomerSurname, pat.PaymentAmount
FROM CardIssueTable cit
INNER JOIN CustomerTable ct ON cit.CustId = Ct.CustId
LEFT JOIN PosTable pt ON pt.PosSerial = #PosSerialNo
LEFT JOIN PaymentTable pat ON pt.PosLocation = pat.PaymentLoaction
WHERE CardNo = #CardNo
END
ELSE
BEGIN
--If not you get: “No Data Found”
SELECT 'No Data Found'
END
END
I am working on a large project with a lot of stored procedures. I came into the following situation where a developer modified the arguments of a stored procedure which was called by another stored procedure.
Unfortunately, nothing prevents the ALTER PROC to complete.
Is there a way to perform those checks afterwards ?
What would be the guidelines to avoid getting into that kind of problems ?
Here is a sample code to reproduce this behavior :
CREATE PROC Test1 #arg1 int
AS
BEGIN
PRINT CONVERT(varchar(32), #arg1)
END
GO
CREATE PROC Test2 #arg1 int
AS
BEGIN
DECLARE #arg int;
SET #arg = #arg1+1;
EXEC Test1 #arg;
END
GO
EXEC Test2 1;
GO
ALTER PROC Test1 #arg1 int, #arg2 int AS
BEGIN
PRINT CONVERT(varchar(32), #arg1)
PRINT CONVERT(varchar(32), #arg2)
END
GO
EXEC Test2 1;
GO
DROP PROC Test2
DROP PROC Test1
GO
Sql server 2005 has a system view sys.sql_dependencies that tracks dependencies. Unfortunately, it's not all that reliable (For more info, see this answer). Oracle, however, is much better in that regard. So you could switch. There's also a 3rd party vendor, Redgate, who has Sql Dependency Tracker. Never tested it myself but there is a trial version available.
I have the same problem so I implemented my poor man's solution by creating a stored procedure that can search for strings in all the stored procedures and views in the current database. By searching on the name of the changed stored procedure I can (hopefully) find EXEC calls.
I used this on sql server 2000 and 2008 so it probably also works on 2005. (Note : #word1, #word2, etc must all be present but that can easily be changed in the last SELECT if you have different needs.)
CREATE PROCEDURE [dbo].[findWordsInStoredProceduresViews]
#word1 nvarchar(4000) = null,
#word2 nvarchar(4000) = null,
#word3 nvarchar(4000) = null,
#word4 nvarchar(4000) = null,
#word5 nvarchar(4000) = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- create temp table
create table #temp
(
id int identity(1,1),
Proc_id INT,
Proc_Name SYSNAME,
Definition NTEXT
)
-- get the names of the procedures that meet our criteria
INSERT #temp(Proc_id, Proc_Name)
SELECT id, OBJECT_NAME(id)
FROM syscomments
WHERE OBJECTPROPERTY(id, 'IsProcedure') = 1 or
OBJECTPROPERTY(id, 'IsView') = 1
GROUP BY id, OBJECT_NAME(id)
-- initialize the NTEXT column so there is a pointer
UPDATE #temp SET Definition = ''
-- declare local variables
DECLARE
#txtPval binary(16),
#txtPidx INT,
#curText NVARCHAR(4000),
#counterId int,
#maxCounterId int,
#counterIdInner int,
#maxCounterIdInner int
-- set up a double while loop to get the data from syscomments
select #maxCounterId = max(id)
from #temp t
create table #tempInner
(
id int identity(1,1),
curName SYSNAME,
curtext ntext
)
set #counterId = 0
WHILE (#counterId < #maxCounterId)
BEGIN
set #counterId = #counterId + 1
insert into #tempInner(curName, curtext)
SELECT OBJECT_NAME(s.id), text
FROM syscomments s
INNER JOIN #temp t
ON s.id = t.Proc_id
WHERE t.id = #counterid
ORDER BY s.id, colid
select #maxCounterIdInner = max(id)
from #tempInner t
set #counterIdInner = 0
while (#counterIdInner < #maxCounterIdInner)
begin
set #counterIdInner = #counterIdInner + 1
-- get the pointer for the current procedure name / colid
SELECT #txtPval = TEXTPTR(Definition)
FROM #temp
WHERE id = #counterId
-- find out where to append the #temp table's value
SELECT #txtPidx = DATALENGTH(Definition)/2
FROM #temp
WHERE id = #counterId
select #curText = curtext
from #tempInner
where id = #counterIdInner
-- apply the append of the current 8KB chunk
UPDATETEXT #temp.definition #txtPval #txtPidx 0 #curtext
end
truncate table #tempInner
END
-- check our filter
SELECT Proc_Name, Definition
FROM #temp t
WHERE (#word1 is null or definition LIKE '%' + #word1 + '%') AND
(#word2 is null or definition LIKE '%' + #word2 + '%') AND
(#word3 is null or definition LIKE '%' + #word3 + '%') AND
(#word4 is null or definition LIKE '%' + #word4 + '%') AND
(#word5 is null or definition LIKE '%' + #word5 + '%')
ORDER BY Proc_Name
-- clean up
DROP TABLE #temp
DROP TABLE #tempInner
END
You can use sp_refreshsqlmodule to attempt to re-validate SPs (this also updates dependencies), but it won't validate this particular scenario with parameters at the caller level (it will validate things like invalid columns in tables and views).
http://www.mssqltips.com/tip.asp?tip=1294 has a number of techniques, including sp_depends
Dependency information is stored in the SQL Server metadata, including parameter columns/types for each SP and function, but it isn't obvious how to validate all the calls, but it is possible to locate them and inspect them.