I am getting below exception when i am going to enter record in a table through StoredProceduer of sqlserver
i have a field which i need u update immediately after insert of new record in table.
for that i created a sotredprocedure in which i wrote insert command first and after that i wrote a update command for same recored but it gave me below error
SQlException:
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2. Uncommittable transaction is detected at the end of the batch. The transaction is rolled back. Some Error in stored procedure execution
i tried in another way also like: i just wrote insert command in storedprocedure and i created a afterInsert trigger in which i am firing update command. but still i am facing above exception
Details:
Table structure:
CREATE TABLE [dbo].[TabStoreGRNMaster](
[pk_grnm_id] [bigint] IDENTITY(1,1) NOT NULL,
[fk_col_id] [bigint] NULL,
[fk_sup_id] [bigint] NULL,
[grnm_grnno] [varchar](50) NULL,
[grnm_date] [nvarchar](10) NULL,
[grnm_partyinvno] [varchar](50) NULL,
[grnm_invdate] [nvarchar](10) NULL,
[grnm_freight] [numeric](7, 2) NULL,
[grnm_otherchrg] [numeric](7, 2) NULL,
[grnm_roundoff] [bit] NULL,
[Fk_User_Id] [bigint] NULL,
[grnm_EntryDate] [nvarchar](8) NULL,
CONSTRAINT [PK_TabStoreGRNMaster] PRIMARY KEY CLUSTERED
(
[pk_grnm_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
storedprocedure:
USE [Kollege]
GO
/****** Object: StoredProcedure [dbo].[StoreGRNMaster] Script Date: 11/27/2009 10:20:37 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[StoreGRNMaster]
(
#pk_grnm_id [bigint] output ,
#fk_col_id [bigint] = 0 ,
#fk_sup_id [bigint] = 0 ,
#grnm_grnno [varchar](50) = '',
#grnm_date [nvarchar](10) = null,
#grnm_partyinvno [varchar](50) = '',
#grnm_invdate [nvarchar](10) = null,
#grnm_freight [numeric] = 0 ,
#grnm_otherchrg [numeric] = 0 ,
#grnm_roundoff [bit] = 0 ,
#Fk_User_Id [bigint] = 0 ,
#grnm_EntryDate [nvarchar](8) = null,
#opt [BIGINT] =0,
#del [bit] =0
)
as
begin
SET NOCOUNT ON;
BEGIN TRY
begin transaction
if isnull(#opt,0) = 0 begin
INSERT INTO TabStoreGRNMaster
(
fk_col_id,
fk_sup_id,
grnm_grnno,
grnm_date,
grnm_partyinvno,
grnm_invdate,
grnm_freight,
grnm_otherchrg,
grnm_roundoff,
Fk_User_Id,
grnm_EntryDate
)
VALUES
(
#fk_col_id,
#fk_sup_id,
#grnm_grnno,
#grnm_date,
#grnm_partyinvno,
#grnm_invdate,
#grnm_freight,
#grnm_otherchrg,
#grnm_roundoff,
#Fk_User_Id,
#grnm_EntryDate
)
set #pk_grnm_id = ##identity
end
else
begin
if #del = 0
UPDATE TabStoreGRNMaster
SET
fk_col_id = #fk_col_id,
fk_sup_id = #fk_sup_id,
grnm_grnno = #grnm_grnno,
grnm_date = #grnm_date,
grnm_partyinvno = #grnm_partyinvno,
grnm_invdate = #grnm_invdate,
grnm_freight = #grnm_freight,
grnm_otherchrg = #grnm_otherchrg,
grnm_roundoff = #grnm_roundoff,
Fk_User_Id = #Fk_User_Id,
grnm_EntryDate = #grnm_EntryDate
WHERE
(
pk_grnm_id = #opt
)
if #del=1 and isnull(#opt,0) <> 0
DELETE from [TabStoreGRNMaster]
WHERE
( [pk_grnm_id] = #opt)
end
commit transaction
END TRY
BEGIN CATCH
raiserror ('Some Error in stored procedure execution',1,1)
END CATCH;
END
Trigger:
alter TRIGGER TGRStoreGRNMasterCode
ON tabStoreGRNMaster
AFTER INSERT
AS
begin
declare #pk varchar(10)
declare #colcode varchar(10)
declare #current_session varchar(20)
declare #colid bigint
set #pk = (select pk_grnm_id from Inserted)
--set #colid = (select fk_col_id from Inserted)
set #colcode= 'jiet'--(select col_code from tabcollegemaster where pk_col_id =5) (when i replace word 'Jiet' with commented qry i gets sql exception otherwise its working fine)
select #current_session = Ses_abbrev from TabAcaSessionMast where ses_current = 1
--update tabStoreGRNMaster set grnm_grnno= #colcode +'/' +#current_session+ '/' + #pk where pk_grnm_id=convert(bigint,#pk)
update tabStoreGRNMaster set grnm_grnno= (select col_code from tabcollegemaster where pk_col_id=5) +'/' +#current_session+ '/' + #pk where pk_grnm_id=convert(bigint,#pk)
end
Your comment to another answer mentioned "I am maintain Transactions from Vb.net also while calling this stored procedure". This is the cause
You have to balance your BEGIN TRAN and COMMITs/ROLLBACKs so ##TRANCOUNT starts and finishes with the same value for the same scope.
Either do it all in the stored proc or do it all in the client
It looks to me like you're not doing anything with the open transaction if an error is found in your TRY block - the COMMIT would not run, but your CATCH block has no ROLLBACK.
Related
I have a database with a memory optimized table. I want to archive this table in another database. I want to write an stored procedure to do that.
I am implemented below sample from 1 and 2 successfully, but in these sample, the first database is not in memory and the second database is in memory.
In my case, the first database is in memory and the second one can be in memory or not.
Here is my code:
1- my table :
USE [TestReport]
GO
/****** Object: Table [dbo].[Report] Script Date: 1/22/2018 4:40:04 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Report]
(
[ReportID] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[Year] [int] NOT NULL,
[DayOfYear] [int] NOT NULL,
[ProductType] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[ApplicationID] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[TotalSize] [bigint] NOT NULL DEFAULT ((0)),
[TotalCount] [bigint] NOT NULL DEFAULT ((0)),
[LastReportTimeSpan] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NULL,
INDEX [idx] NONCLUSTERED HASH
(
[ReportID],
[DayOfYear]
)WITH ( BUCKET_COUNT = 131072),
CONSTRAINT [pk] PRIMARY KEY NONCLUSTERED HASH
(
[ReportID],
[Year],
[DayOfYear],
[ProductType],
[ApplicationID]
)WITH ( BUCKET_COUNT = 131072)
)WITH ( MEMORY_OPTIMIZED = ON , DURABILITY = SCHEMA_AND_DATA )
GO
2- simple Stored procedure
CREATE PROCEDURE [dbo].[ArchiveReport]
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS BEGIN ATOMIC WITH
(
TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english'
)
BEGIN
DECLARE #currentdate DATETIME2;
SET #currentdate = GETDATE();
declare #maintainDay INT = 5
INSERT TestReportArchive.[dbo].Report
SELECT [ReportID],
[Year],
[DayOfYear],
[ProductType],
[ApplicationID],
[TotalSize],
[TotalCount],
[LastReportTimeSpan]
FROM [dbo].[Report]
WHERE DATEADD(day, [DayOfYear] + #maintainDay, DATEADD(YEAR, [Year] - 1900, 0)) > #currentdate;
DELETE FROM [dbo].[Report]
WHERE DATEADD(day, [DayOfYear] + #maintainDay, DATEADD(YEAR, [Year] - 1900, 0)) > #currentdate;
END;
END
3- simple stored procedure error
Msg 4512, Level 16, State 3, Procedure ArchiveReport, Line 12
Cannot schema bind procedure 'dbo.ArchiveReport' because name 'TestReportArchive.dbo.Report' is invalid for schema binding. Names must be in two-part format and an object cannot reference itself.
TestReportArchive is my destination database
4- using 1 and 2. definition of table variable
USE [TestReport]
GO
/****** Object: UserDefinedTableType [dbo].[MemoryType] Script Date: 1/22/2018 4:35:14 PM ******/
CREATE TYPE [dbo].[MemoryType] AS TABLE(
[ReportID] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[Year] [int] NOT NULL,
[DayOfYear] [int] NOT NULL,
[ProductType] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[ApplicationID] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NOT NULL,
[TotalSize] [bigint] NOT NULL,
[TotalCount] [bigint] NOT NULL,
[LastReportTimeSpan] [nvarchar](50) COLLATE Latin1_General_100_BIN2 NULL,
INDEX [idx] NONCLUSTERED HASH
(
[ReportID],
[DayOfYear]
)WITH ( BUCKET_COUNT = 131072)
)
WITH ( MEMORY_OPTIMIZED = ON )
GO
5- stored procedure with table variable
CREATE PROCEDURE [dbo].[ArchiveReport]
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS BEGIN ATOMIC WITH
(
TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english'
)
BEGIN
DECLARE #currentdate DATETIME2;
SET #currentdate = GETDATE();
declare #maintainDay INT = 5
DECLARE #InMem [dbo].[MemoryType];
INSERT #InMem
SELECT [ReportID],
[Year],
[DayOfYear],
[ProductType],
[ApplicationID],
[TotalSize],
[TotalCount],
[LastReportTimeSpan]
FROM [dbo].[Report]
WHERE DATEADD(day, [DayOfYear] + #maintainDay, DATEADD(YEAR, [Year] - 1900, 0)) > #currentdate;
INSERT TestReportArchive.[dbo].[Report]
SELECT [ReportID],
[Year],
[DayOfYear],
[ProductType],
[ApplicationID],
[TotalSize],
[TotalCount],
[LastReportTimeSpan]
FROM #InMem
DELETE FROM [dbo].[Report]
WHERE DATEADD(day, [DayOfYear] + #maintainDay, DATEADD(YEAR, [Year] - 1900, 0)) > #currentdate;
END;
END
6- Error from 5 stored procedure
Msg 4512, Level 16, State 3, Procedure ArchiveReport, Line 25
Cannot schema bind procedure 'dbo.ArchiveReport' because name 'TestReportArchive.dbo.Report' is invalid for schema binding. Names must be in two-part format and an object cannot reference itself.
TestReportArchive is my destination database
Cross-database queries involving Memory-Optimized Tables are not supported.
Unsupported SQL Server Features for In-Memory OLTP
A query cannot access other databases if the query uses either a
memory-optimized table or a natively compiled stored procedure. This
restriction applies to transactions as well as to queries.
Ultimately I created a non-memory-optimized table (ReportTemp) on the testReport (first Database) and change the stored procedure to insert data from Report Table to ReportTemp Table in the first database. Then I write another SP to move Data to archive Database.
I have 2 tables User and UserLogin. UserLogin have a foreign key relationship with User table. What I want to do here is whenever I insert data into the User table through my API their autogenerated(user_id) auto-inserted into UserLogin table.
User table:
user_id | user_name | user_email
UserLogin table:
user_id | user_password | user_number
So when I run my query to add name and email in User table then autoincremented user_id is automatically inserted in UserLogin table with the provided password and number. How can I achieve this and is that thread safe?
yes it is possible and usually can be optained by ##identity try something like
set nocount off;
insert into User Values("Name","Email")
declare #lastID = ##identity
insert into UserLogin values(#lastID,"Password","number")
This code helps you
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[User](
[user_id] [int] IDENTITY(1,1) NOT NULL,
[user_name] [varchar](100) NULL,
[user_email] [varchar](100) NULL,
[salt] [uniqueidentifier] NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
[user_id] 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
SET ANSI_PADDING OFF
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[UserLogin](
[UserLoginId] [int] IDENTITY(1,1) NOT NULL,
[user_id] [int] NULL,
[user_password] [binary](1) NULL,
[user_number] [int] NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[User] WITH CHECK ADD CONSTRAINT [FK_UserLogin_User] FOREIGN KEY([user_id])
REFERENCES [dbo].[User] ([user_id])
GO
ALTER TABLE [dbo].[User] CHECK CONSTRAINT [FK_UserLogin_User]
GO
CREATE PROC [dbo].[Usp_UserLogin]
(
#user_name VARCHAR(100)
,#user_email VARCHAR(100)
,#user_password VARCHAR(200)
,#user_number INT
)
AS
Begin
SET NOCOUNT ON
DECLARE #Salt UNIQUEIDENTIFIER =NEWID()
,#IdentityNUmber INT
,#responseMessage nvarchar(1000)
BEGIN TRY
INSERT INTO Dbo.[User]([user_name],[user_email],[salt])
SELECT #user_name
,#user_email
,#salt
SET #IdentityNUmber=SCOPE_IDENTITY()
INSERT INTO Dbo.[UserLogin]([user_id],[user_password],user_number)
SELECT
#IdentityNUmber
,#user_number
,HASHBYTES('SHA2_512', #user_password + CAST(#salt AS NVARCHAR(36)))
END TRY
BEGIN CATCH
SET #responseMessage=ERROR_MESSAGE()
END CATCH
END
GO
Execute the Procedure
EXEC [Usp_UserLogin] #user_name='Test1',#user_email='Test1#gmail',#user_password='Test1#123',#user_number=2
I have a trigger set up to insert into a table and then want to have a broker job scheduled to send emails from said table. I have the trigger working and I thought I had the SP to send emails working right but my loop gets stuck and sends hundreds of emails before I cancel the SP. Any thoughts on what I've done wrong? I'm using BatchEmailID as the flag to know what needs to be sent and what doesn't where '0' = it hasn't been sent and needs to go and '1' = it has been sent so ignore.
Create Table:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tb_BatchEmail](
[BatchEmailID] [bit] NULL,
[To] [varchar](50) NULL,
[Body] [varchar](255) NULL,
[Subject] [varchar](20) NULL,
[Profile] [varchar](50) NULL,
[OrderID] [varchar](25) NULL,
[OrderDateTime] [datetime] NULL,
[SentDateTime] [datetime] NULL
) ON [PRIMARY]
GO
insert values:
INSERT INTO tb_BatchEmail
VALUES (
'0'
,'someemail#address.com'
,'msg body'
,'Test Subject'
,'dbmail profile'
,'123456.001'
,'6/4/2015'
,NULL
),
(
'0'
,'someemail#address.com'
,'msg body'
,'Test Subject'
,'dbmail profile'
,'123456.002'
,'6/4/2015'
,NULL
)
sp_send_dbmail:
while 1=1
begin
declare #BatchEmailID bit
declare #To varchar (25)
declare #Body varchar (250)
declare #Subject varchar (25)
declare #ProfileName varchar (20)
select top 1
#BatchEmailID = BatchEmailID,
#To = [To],
#Body = Body,
#Subject = [Subject],
#ProfileName = [Profile]
from tb_BatchEmail
where BatchEmailID = 0
if(#BatchEmailID is null)
break;
EXEC msdb.dbo.sp_send_dbmail #recipients = #To
,#body = #Body
,#subject = #Subject
,#profile_name = #ProfileName
update tb_BatchEmail
set BatchEmailID = 1, SentDateTime = GETDATE()
where BatchEmailID = #BatchEmailID
end
OK first off, to update the table, you need a unique value on each row.
Alter your table as follows:
CREATE TABLE [dbo].[tb_BatchEmail](
[Id] int identity(1,1),
[BatchEmailID] [bit] NULL,
[To] [varchar](50) NULL,
[Body] [varchar](255) NULL,
[Subject] [varchar](20) NULL,
[Profile] [varchar](50) NULL,
[OrderID] [varchar](25) NULL,
[OrderDateTime] [datetime] NULL,
[SentDateTime] [datetime] NULL
) ON [PRIMARY]
GO
The new [Id] column will be used to reference back the row in question.
The your loop becomes this (with a test table used), just comment out my select, and uncomment the email bit:
declare #tb_BatchEmail table (Id int identity(1,1),
BatchEmailID bit,
[To] varchar(25),
Body varchar(250),
[Subject] varchar(25),
[Profile] varchar(20),
SentDateTime datetime)
insert into #tb_BatchEmail
select 0,'joe#domain.com','just a test','test','myprofile',null
declare #Id int
declare #To varchar (25)
declare #Body varchar (250)
declare #Subject varchar (25)
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
select #Id, #To, #Body, #Subject, #ProfileName
update #tb_BatchEmail
set BatchEmailID = 1, SentDateTime = GETDATE()
where Id = #Id
end
i have the following stored procedure.
alter proc uspUpdtStudent
#pStudID int,
#pTitle char(10),
#pFName varchar(50),
#pLName varchar(50),
#pDOB date,
#pGender char(1),
#pIsPriorStud bit,
#pCitizen varchar(50),
#pResidency varchar(50),
#pPic varbinary(max),
--#pOldContact as dbo.Contact readonly,
#pNewContact as dbo.Contact readonly,
#pProgTrack tinyint,
#pProgID int,
#pid int output -- why not EnrID?
as
begin
SET NOCOUNT ON;
declare #tblNew as table (rw_id int identity(1,1), addL1 varchar(200), sub varchar(100), town varchar(100), post int)
select #pTitle, #pFName, #pLName, #pDOB, #pGender, #pIsPriorStud, #pCitizen, #pResidency, #pPic, #pStudID
update dbo.Students
set
Title=#pTitle,
FName=#pFName,
LName=#pLName,
DOB=#pDOB,
Gender=#pGender,
IsPriorStud=#pIsPriorStud,
Citizenship=#pCitizen,
Residency=#pResidency,
StudImg=#pPic,
DateOfRago=GETDATE()
where StudID =#pStudID
select #pStudID as 'Passed Student ID'
declare #rowcount int
set #pid = SCOPE_IDENTITY()
--select #pid
set #rowcount = ##ROWCOUNT
select #rowcount as 'Effected Row count'
if #rowcount > 0
begin
SELECT #pid as 'Student table row ID'
end
else
begin
set #pid = -1
--rollback tran
return 302
end
end
go
Then i pass theses values to the stored procedure
USE [SMSV1]
GO
declare #p13 int
set #p13=-1
declare #p14 dbo.Contact
insert into #p14 values(N'fyyyfyf',N'woeoeoo',N'kokokok',N'123456')
exec uspUpdtStudent #pStudID=100000007,#pTitle=N'Mr.',#pFName=N'George',#pLName=N'kadafi',#pDOB='1940-12-12 00:00:00',#pGender=N'M',#pIsPriorStud=0,#pCitizen=N'LIBIYA',#pResidency=N'LIBIYA',#pPic=null,#pProgID=15,#pProgTrack=2,#pid=#p13 output,#pNewContact=#p14
what is funny about is, it adds a row to the student table but when i tried to access the row id from SCOPE_IDENTITY() it shows as NULL. the IF condition executes because ##ROWCOUNT is greater than zero also As you can see in the code i have even saved the id value in a variable #pid. I have attached this video on youtube so it might help to understand understand the situation.
Here is my student table
USE [SMSV1]
GO
/****** Object: Table [dbo].[Students] Script Date: 12/18/2014 07:39:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Students](
[ID] [int] IDENTITY(1,1) NOT NULL,
[StudID] [int] NULL,
[Title] [char](10) NULL,
[FName] [varchar](50) NULL,
[LName] [varchar](50) NULL,
[DOB] [date] NULL,
[Gender] [char](1) NULL,
[IsPriorStud] [bit] NULL,
[Citizenship] [varchar](50) NULL,
[Residency] [varchar](50) NULL,
[StudImg] [varbinary](max) NULL,
[DateOfRago] [datetime] NULL,
[Updt] [datetime] NOT NULL,
[IsActive] [bit] NULL,
CONSTRAINT [PK_Students] PRIMARY KEY CLUSTERED
(
[ID] 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
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Students] ADD CONSTRAINT [DF_Students_Updt] DEFAULT (getdate()) FOR [Updt]
GO
thanks
##ROWCOUNT gets reset per each statement. Try the following to see:
DECLARE #Test INT;
SELECT 10 UNION ALL SELECT 20;
SELECT ##ROWCOUNT;
SELECT 10 UNION ALL SELECT 20;
SET #Test = 1;
SELECT ##ROWCOUNT;
Returns:
10
20
2
10
20
1 -- this is 1 instead of 2 due to the SET command being between the second two SELECTs
If you want SET #RowCount = ##ROWCOUNT; to be accurate, it has to be the next statement after the UPDATE. Where you currently have it (i.e. after a SET command) #rowcount will always be 1 no matter what happens with the UPDATE.
Also, there is no INSERT, so SCOPE_IDENTITY() would have to return NULL. And why would you need to dynamically get the ID anyway? Isn't it being passed into the proc via #pStudID? If for some reason the [StudID] field in the [Students] table is not the IDENTITY field, you can still get that via the OUTPUT clause:
UPDATE dbo.Students
SET
Title=#pTitle,
FName=#pFName,
LName=#pLName,
DOB=#pDOB,
Gender=#pGender,
IsPriorStud=#pIsPriorStud,
Citizenship=#pCitizen,
Residency=#pResidency,
StudImg=#pPic,
DateOfRago=GETDATE()
OUTPUT INSERTED.ID -- this is the IDENTITY field as per the CREATE TABLE statement
WHERE StudID = #pStudID;
Using the OUTPUT clause in this manner will result in a 1 row, 1 column result set ONLY IF a row is updated. If there is no matching row, there is no result set. If you want a clearer indication of no row updated than merely no result set, as I mentioned above, put the SET #RowCount = ##ROWCOUNT; just after the UPDATE and then you can test for IF (#RowCount = 0)....
IF you need the ID field in the #pid variable since it is an OUTPUT parameter, then you need to capture the result set of the UPDATE...OUTPUT into a temp table or table variable:
DECLARE #UpdatedID TABLE (ID INT);
UPDATE dbo.Students
SET
Title=#pTitle,
FName=#pFName,
LName=#pLName,
DOB=#pDOB,
Gender=#pGender,
IsPriorStud=#pIsPriorStud,
Citizenship=#pCitizen,
Residency=#pResidency,
StudImg=#pPic,
DateOfRago=GETDATE()
OUTPUT INSERTED.ID -- this is the IDENTITY field as per the CREATE TABLE statement
INTO #UpdatedID (ID)
WHERE StudID = #pStudID;
SELECT #pid = ID
FROM #UpdatedID;
IF (#pid IS NULL)
BEGIN
SET #pid = -1;
RETURN 302;
END;
From SCOPE_IDENTITY (Transact-SQL) (Bold for emphasis mine)
Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You are doing an Update, not an insert, hence it is not being set.
I have the following tables:
MySQL table: member_interact
CREATE TABLE `member_interact` (
`INT_MEMBER_ID` int(11) NOT NULL,
`INT_ID` int(11) NOT NULL AUTO_INCREMENT,
`INT_SOURCE` varchar(1) NOT NULL,
`INT_DATE` datetime DEFAULT NULL,
`INT_TYPE` varchar(30) NOT NULL,
`COPY_TO_STG` varchar(12) NOT NULL DEFAULT 'NO',
`NEW_STG_SEQ` int(11) DEFAULT NULL,
`COPY_TO_STG_DATE` datetime DEFAULT NULL,
PRIMARY KEY (`INT_ID`),
UNIQUE KEY `INT_ID_UNIQUE` (`INT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=31246 DEFAULT CHARSET=utf8$$
Oracle table: MEMBER_INTERACT_MYSQL_STG
CREATE TABLE "JTI_HTP"."MEMBER_INTERACT_MYSQL_STG"
( "INT_MEMBER_ID" NUMBER(10,0) NOT NULL ENABLE,
"INT_ID" NUMBER(10,0),
"INT_SOURCE" NVARCHAR2(1) NOT NULL ENABLE,
"INT_DATE" DATE,
"INT_TYPE" NVARCHAR2(30) NOT NULL ENABLE,
"INSERTING_DATE" DATE,
"MYSQL_ID" NUMBER(12,0)
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
TABLESPACE "USERS" ;
Basically, I need to copy member_interact into member_interact_mysql_stg with adding new columns as follow:
MEMBER_INTERACT_MYSQL_STG.STG_INT_ID = NEW_SEQ
MEMBER_INTERACT_MYSQL_STG.MYSQL_INT_ID = MEMBER_INTERACT.INT_ID
MEMBER_INTERACT.COPY_TO_STG = 'YES', once the copy operation is completed.
MEMBER_INTERACT.NEW_STG_SEQ = MEMBER_INTERACT_MYSQL_STG.STG_INT_ID
I have created the following Procedures:
create or replace PROCEDURE COPY_MYSQL_MOB_INT_TO_STG(
P_BATCH_NO IN NUMBER)
IS
CURSOR src
IS
SELECT *
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
WHERE "NEW_STG_SEQ" IS NULL
AND "INT_ID" <= 7000;
STG_INT_ID NUMBER;
BEGIN
FOR des IN src
LOOP
STG_INT_ID := STG_SEQ.NEXTVAL;
INSERT
INTO MEMBER_INTERACT_MYSQL_STG VALUES
(
DES.INT_MEMBER_ID,
STG_INT_ID,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
);
UPDATE_COPIED_MEMBER_INTERACT(STG_INT_ID, DES.INT_ID);
COMMIT;
END LOOP;
END;
create or replace PROCEDURE UPDATE_COPIED_MEMBER_INTERACT( STG_INT_ID IN NUMBER, MYSQL_INT_ID IN NUMBER)
IS
BEGIN
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP"
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = STG_INT_ID
WHERE "INT_ID" = MYSQL_INT_ID;
END;
In fact, there were one procedure to update both tables, but due the error I received I find it might be easier to eliminate the eror by separating the procedure into two.
The error I get is :
ORA-02047: cannot join the distributed transaction in progress
ORA-06512: at "JTI_HTP.UPDATE_COPIED_MEMBER_INTERACT", line 19
ORA-06512: at "JTI_HTP.COPY_MYSQL_MOB_INT_TO_STG", line 28
ORA-06512: at line 6
line 19 is where the second procedure is called. Which I suspected that something has to do with the MySQL table update.
UPDATE
I have updated my script based on #Maheswaran Ravisankar answer as follow:
CREATE OR REPLACE PROCEDURE COPY_MYSQL_MOB_INT_TO_STG_V3(
P_BATCH_NO IN NUMBER)
IS
BEGIN
INSERT INTO MEMBER_INTERACT_MYSQL_STG
SELECT "INT_MEMBER_ID",
STG_SEQ.NEXTVAL,
"INT_SOURCE",
"INT_DATE",
"INT_TYPE",
CURRENT_DATE,
"INT_ID"
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL;
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" =
(SELECT STG_INT_ID
FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A."INT_ID" = B.STG_INT_ID
);
END;
However, I am getting error ORA-02070: database JTIPARTNER_HTP does not support subqueries in this context.
INSERT
INTO MEMBER_INTERACT_MYSQL_STG
SELECt
DES.INT_MEMBER_ID,
STG_SEQ.NEXTVAL,
des.int_source,
des.int_date,
des.int_type,
NULL,
DES.INT_ID
FROM "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" des
WHERE "NEW_STG_SEQ" IS NULL
/* RETURNING STG_INT_ID BULK COLLECT INTO SOME RECORD; --Needed if only processed in array!*/
And update like below,
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = (SELECT STG_INT_ID FROM MEMBER_INTERACT_MYSQL_STG B
WHERE A.INT_ID = B.INT_ID);
(OR)
FOR REC IN (SELECT STG_INT_ID,INT_ID FROM MEMBER_INTERACT_MYSQL_STG)
LOOP
UPDATE "jtipartn_mydb"."MEMBER_INTERACT"#"JTIPARTNER_HTP" A
SET "COPY_TO_STG" = 'YES',
"NEW_STG_SEQ" = REC.STG_INT_ID
WHERE A.INT_ID = REC.INT_ID;
END LOOP;