I am working with a bank database with two tables i.e [Card] and [Transaction].
I have created a stored procedure login that gets as inputs pin and cardNumber and returns the validity of card in an output parameter. Now, I have created another stored procedure withdraw that gets inputs pin, cardNum, transactionAmount and starts a transaction. I am trying to use p1 procedure to handle the validity part. Here are the 2 procedures
create procedure login
#status int output,
#pin varchar(4),
#cnum varchar(20)
as
begin
if exists (select * from [Card] where PIN = #pin AND cardNum = #cnum)
begin
set #status = 1
end
else
begin
set #status = 0
end
end
alter procedure WithDraw
#pin varchar(4),
#cnum varchar(20),
#trAmount int
as
begin
declare #m int
exec login #pin = N'0234', #cnum = N'2324325423336', #status = #m OUTPUT
if (select #m) = 1
--if exists (select * from [Card] where cardNum = #cnum AND pin = #pin)
--working fine with above statement
begin
if exists (select * from [Card]
where cardNum = #cnum AND pin = #pin AND (balance > #trAmount))
begin
update [Card]
set balance = balance - #trAmount
where cardNum = #cnum AND pin = #pin
declare #maxID int
select #maxID = MAX(transId) from [Transaction]
insert into [Transaction]
values (#maxID + 1, GETDATE(), #cnum, #trAmount, 1)
print 'Transaction successful'
end
else
begin
select #maxID = MAX(transId) from [Transaction]
insert into [Transaction]
values(#maxID + 1, GETDATE(), #cnum, #trAmount, 4)
print 'Transaction unsuccessful! Insufficient balance in card'
end
end
else
begin
print 'login failed'
end
end
exec WithDraw #pin = N'1770', #cnum = N'1324327436569', #trAmount = 50000
However, when I execute withdraw with login procedure inside, login always fails. When i execute without login procedure everything works fine. Any help will be greatly appreciated.
Related
I have the following stored procedure in MSSQL
USE [db_DEV]
GO
/****** Object: StoredProcedure [dbo].[DeleteInvoice] Script Date: 11-02-2021 15:29:39 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[DeleteInvoice]
#InvoiceNo AS VARCHAR(50),
#ResultOutput BIT OUTPUT
AS
DECLARE #InvoiceId UNIQUEIDENTIFIER
DECLARE #PayrollId UNIQUEIDENTIFIER
DECLARE #CustomerId UNIQUEIDENTIFIER
DECLARE #Result AS BIT
DECLARE #TransactionTypeId AS INT
DECLARE #InvoiceStatus AS INT
BEGIN
SET XACT_ABORT ON
BEGIN TRY
SELECT #InvoiceId = Id, #CustomerId = CustomerId, #TransactionTypeId = TransactionTypeId, #InvoiceStatus = [Status] FROM Invoice WHERE InvoiceNo=#InvoiceNo;
/* Check if an invoice is in Open, In Review or Pending Approval status and if it's not of payment type */
IF (#InvoiceStatus = 1 OR #InvoiceStatus = 2 OR #InvoiceStatus = 3) AND (#TransactionTypeId < 6)
BEGIN
BEGIN TRAN
SELECT #PayrollId = Id FROM Payroll WHERE InvoiceId = #InvoiceId;
/* Check if an invoice is a payroll */
IF #TransactionTypeId = 1
BEGIN
DELETE FROM PayrollItemFee WHERE PayrollItemId IN (SELECT Id from PayrollItem WITH (NOLOCK) WHERE PayrollId = #PayrollId);
DELETE FROM PayrollItemBenefits WHERE PayrollItemId IN (SELECT Id from PayrollItem WITH (NOLOCK) WHERE PayrollId = #PayrollId);
DELETE FROM PayrollChangeItem WHERE PayrollId = #PayrollId;
DELETE FROM PayrollItem WHERE PayrollId = #PayrollId;
DELETE FROM PayrollFee WHERE PayrollId = #PayrollId;
DELETE FROM Payroll WHERE Id = #PayrollId;
DELETE FROM Activity WHERE CustomerId = #CustomerId AND [DATA] = 'New Payroll invoice added ' + #InvoiceNo
END
DELETE FROM TransactionHistory WHERE RecordId = #InvoiceId
DELETE FROM OpenTask WHERE RelatedEntityId = #InvoiceId
DELETE FROM InvoiceDocument WHERE InvoiceId = #InvoiceId;
DELETE FROM InvoiceNote WHERE InvoiceId = #InvoiceId;
DELETE FROM InvoiceRelated WHERE InvoiceId = #InvoiceId;
DELETE FROM InvoiceRelated WHERE RelatedInvoiceId = #InvoiceId;
DELETE FROM InvoiceItem WHERE InvoiceId = #InvoiceId;
DELETE FROM Invoice WHERE Id = #InvoiceId;
SET #Result=1
COMMIT TRAN
END
ELSE
SET #Result = 0
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
ROLLBACK TRAN
PRINT(ERROR_MESSAGE())
SET #Result=0
END
END CATCH
SELECT #Result AS ResultOutput
END
GO
I have tried to convert it into MySQL
USE db_DEV;
DELIMITER //
CREATE PROCEDURE DeleteInvoice (
InvoiceNo VARCHAR(50),
OUT ResultOutput TINYINT )
BEGIN
DECLARE InvoiceId CHAR(36);
DECLARE PayrollId CHAR(36);
DECLARE CustomerId CHAR(36);
DECLARE Result TINYINT;
DECLARE TransactionTypeId INT;
DECLARE InvoiceStatus INT;
BEGIN
SET XACT_ABORT ON
BEGIN TRY
SELECT Id, CustomerId, TransactionTypeId, Status INTO InvoiceId, CustomerId, TransactionTypeId, InvoiceStatus FROM Invoice WHERE InvoiceNo=InvoiceNo;
IF (InvoiceStatus = 1 OR InvoiceStatus = 2 OR InvoiceStatus = 3) AND (TransactionTypeId < 6)
THEN
START TRANSACTION;
SELECT Id INTO PayrollId FROM Payroll WHERE InvoiceId = InvoiceId;
IF TransactionTypeId = 1
THEN
DELETE FROM PayrollItemFee WHERE PayrollItemId IN (SELECT Id from PayrollItem WITH; (NOLOCK) WHERE PayrollId = PayrollId);
DELETE FROM PayrollItemBenefits WHERE PayrollItemId IN (SELECT Id from PayrollItem WITH; (NOLOCK) WHERE PayrollId = PayrollId);
DELETE FROM PayrollChangeItem WHERE PayrollId = PayrollId;
DELETE FROM PayrollItem WHERE PayrollId = PayrollId;
DELETE FROM PayrollFee WHERE PayrollId = PayrollId;
DELETE FROM Payroll WHERE Id = PayrollId;
DELETE FROM Activity WHERE CustomerId = v_CustomerId AND `DATA` = CONCAT('New Payroll invoice added ' , p_InvoiceNo);
END IF;
DELETE FROM TransactionHistory WHERE RecordId = InvoiceId;
DELETE FROM OpenTask WHERE RelatedEntityId = InvoiceId;
DELETE FROM InvoiceDocument WHERE InvoiceId = InvoiceId;
DELETE FROM InvoiceNote WHERE InvoiceId = InvoiceId;
DELETE FROM InvoiceRelated WHERE InvoiceId = InvoiceId;
DELETE FROM InvoiceRelated WHERE RelatedInvoiceId = InvoiceId;
DELETE FROM InvoiceItem WHERE InvoiceId = InvoiceId;
DELETE FROM Invoice WHERE Id = InvoiceId;
SET Result=1;
COMMIT ;
ELSE
SET Result = 0;
END IF;
END; TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
THEN
ROLLBACK;
SET Result=0;
END IF;
END; CATCH
SELECT Result AS ResultOutput;
END//
//
DELIMITER ;
But I am getting the following error.
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'ON BEGIN TRY SELECT Id, CustomerId, TransactionTypeId, Status INTO ' at line 14
I doubt the error has to do something with the usage of
SET XACT_ABORT ON
Also need some help in converting TRY CATCH with EXIT HANDLER
I'm relatively new to databases and I'm trying to get this done without the help of our DB team.
Can anybody guide me on what I am doing wrong here?
I want to save with Stored Procedure. Please check my script first
`USE [Payroll]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[ResignSave]
(
#ResignCode varchar(50),
#Nip Varchar(50),
#Keterangan Varchar(50),
#ResignDate Varchar(50),
#CreatedBy varchar(50),
#CreatedDate date,
#msg varchar(25) = NULL
)
AS
BEGIN
Begin Try
set #ResignCode = (select case
when right(max(ResignCode),7) is null then 'RC0000001'
else ('RC' + RIGHT('0000000' + cast(right(max(ResignCode),7) + 1 as nvarchar),7))
end ResignCode from Resign)
INSERT INTO Resign(ResignCode,Nip, Keterangan, ResignDate, CreatedBy,CreatedDate)
VALUES(#ResignCode,#Nip,#Keterangan, #ResignDate,#CreatedBy,GETDATE())
end try
Begin Catch
Select ERROR_NUMBER() as ErrorNumber, ERROR_MESSAGE() as ErrorMessage
End Catch
End
`
My Stored Procedure working fine. My question is, is there anyway to checking the input if it's exists in my table then set it to my #msg.
You might be looking for below code.
ALTER Procedure [dbo].[ResignSave]
(
#ResignCode varchar(50),
#Nip Varchar(50),
#Keterangan Varchar(50),
#ResignDate Varchar(50),
#CreatedBy varchar(50),
#CreatedDate date,
#msg varchar(25) = NULL
)
AS
BEGIN
Begin Try
if exists (select * from Resign where ResignCode = #ResignCode and Nip = #Nip and ResignDate = #ResignDate) then
BEGIN
set #msg = 'Record already exists'
select #msg AS ProcResult
END
set #ResignCode = (select case
when right(max(ResignCode),7) is null then 'RC0000001'
else ('RC' + RIGHT('0000000' + cast(right(max(ResignCode),7) + 1 as nvarchar),7))
end ResignCode from Resign)
INSERT INTO Resign(ResignCode,Nip, Keterangan, ResignDate, CreatedBy,CreatedDate)
VALUES(#ResignCode,#Nip,#Keterangan, #ResignDate,#CreatedBy,GETDATE())
SELECT 'Insert Successful' AS ProcResult
end try
Begin Catch
Select 'Insert Failed:' + cast(ERROR_NUMBER() as varchar) + ERROR_MESSAGE() AS ProcResult
End Catch
End
If this is what you are looking for, you don't need the #msg parameter. juts execute the procedure and get the returned result set
When trying to run the following stored procedure from django, I get an OperationError (1172, 'Result consisted of more than one row') Any idea what I might be doing wrong?
-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `UpdatePrices`(IN storeId int, IN bottleSize VARCHAR(50))
BEGIN
DECLARE amount DECIMAL(10,2); DECLARE isCustom INT DEFAULT 0;
DECLARE changeType VARCHAR(50) DEFAULT 'State'; DECLARE updateType INT DEFAULT 0;
IF bottleSize = '1000 Ml' THEN
SELECT S1000IncreaseChoices INTO changeType FROM store_store WHERE StoreID = storeId;
IF changeType = 'State' THEN
SELECT updateType = 0;
END IF;
IF changeType = 'Flat' THEN
SELECT S1000IncreaseAmount INTO amount FROM store_store WHERE StoreID = storeId;
SELECT updateType = 1;
END IF;
IF changeType = 'Percent' THEN
SELECT 1 - S1000IncreaseAmount/100 INTO amount FROM store_store WHERE StoreID = storeId;
SELECT updateType = 2;
END IF;
END IF;
IF updateType = 0 THEN
update store_storeliquor SL
inner join liquor_liquor LL
on liquorID_id = id
set StorePrice = ShelfPrice
where BottleSize = bottleSize
and storeID_id = storeId
and custom = 0;
END IF;
IF updateType = 1 THEN
update store_storeliquor SL
inner join liquor_liquor LL
on liquorID_id = id
set StorePrice = OffPremisePrice + amount
where BottleSize = bottleSize
and storeID_id = storeId
and custom = 0;
END IF;
IF updateType = 1 THEN
update store_storeliquor SL
inner join liquor_liquor LL
on liquorID_id = id
set StorePrice = OffPremisePrice / amount
where BottleSize = bottleSize
and storeID_id = storeId
and custom = 0;
END IF;
END
I'm not sure if it matters, but I initiate the stored procedure like so:
def priceupdate(request, store_id):
cursor = connection.cursor()
cursor.callproc("UpdatePrices", (store_id, '1000 ML'))
cursor.close()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
Your SELECT...INTO queries give result sets with more then one record. The WHERE filters are incorrect - they compare two the same values StoreID = storeId. Rename IN storeId int parementer to another name. For example - IN storeId_param int
The query will be like this -
SELECT S1000IncreaseChoices INTO changeType FROM store_store WHERE StoreID = storeId_param;
This is a Bug and you need to apply something like that:
SELECT id,data INTO x,y FROM test.t1 LIMIT 1;
I have written the following stored procedure which in HeidiSQL is giving me an Error 1064 at the line starting with SET pay_ref = SELECT CONCAT('KOS' ...
Let me firstly explain what's going on with this procedure. I have a table gamers with a BIGINT primary key with auto_increment. This proc is supposed to:
Take in some params from the user
Check if the user already exists in the db according to his/her email address, and spits back the word "DUPLICATE" if a reord does exist
Else it does the insert as normal
Then it reads in the ID of the new record created and converts it to a varchar, pads it with leading zeros and then gets concatenated with some other strings
This new string (which should read for example KOS00001ABCDEF) then gets updated to the pay_refcode field >>> this is how we have settled on generating a unique payment reference for the user
If all works out well it updates retval with the newly generated reference code to be read by PHP script.
DELIMITER //
CREATE PROCEDURE `InsertGamer` (
IN p_fname VARCHAR(30),
IN p_lname VARCHAR(30),
IN p_email VARCHAR(255),
IN p_favgame VARCHAR(60),
IN p_pay_suffix VARCHAR(6),
OUT retval VARCHAR(14)
)
BEGIN
DECLARE last_id BIGINT;
DECLARE pay_ref VARCHAR(14);
IF (EXISTS(SELECT * FROM gamers WHERE (email = p_email))) THEN
SET retval = 'DUPLICATE';
ELSE
INSERT INTO gamers (fname, lname, email, favgame, pay_refcode)
VALUES (p_fname, p_lname, p_email, p_favgame, NULL);
SET last_id = LAST_INSERT_ID();
SET pay_ref = SELECT CONCAT('KOS', (SELECT LPAD(CONVERT(last_id, VARCHAR(5)),5,'0')), p_pay_suffix);
UPDATE gamers
SET pay_refcode = pay_ref
WHERE application_id = last_id;
SET retval = pay_ref;
END IF;
END //
I cannot for the life of me figure out what the problem is and would sincerely appreciate any help from you. Thank you very much in advance!
You just need to remove the SELECT keyword from line which you set the value for pay_ref.
SET pay_ref = CONCAT('KOS', LPAD(CONVERT(last_id, CHAR(5)),5,'0'), p_pay_suffix);
full code:
DELIMITER //
CREATE PROCEDURE `InsertGamer` (
IN p_fname VARCHAR(30),
IN p_lname VARCHAR(30),
IN p_email VARCHAR(255),
IN p_favgame VARCHAR(60),
IN p_pay_suffix VARCHAR(6),
OUT retval VARCHAR(14)
)
BEGIN
DECLARE last_id BIGINT;
DECLARE pay_ref VARCHAR(14);
SET #count := (SELECT COUNT(*) FROM gamers WHERE email = p_email)
IF (#count > 0) THEN
SET retval = 'DUPLICATE';
ELSE
INSERT INTO gamers (fname, lname, email, favgame, pay_refcode)
VALUES (p_fname, p_lname, p_email, p_favgame, NULL);
SET last_id = LAST_INSERT_ID();
SET pay_ref = CONCAT('KOS', LPAD(CONVERT(last_id, CHAR(5)),5,'0'), p_pay_suffix);
UPDATE gamers
SET pay_refcode = pay_ref
WHERE application_id = last_id;
SET retval = pay_ref;
END IF;
END //
DELIMITER ;
I'm trying to get this SP to return (leave) if some conditions fails and so forth.
This code validates and it saves the procedure, but when I call the procedure with:
CALL ACH_Deposit(30027616,3300012003,200.00,"USD", "127.0.0.1")
It fails with error: "Procedure can't return a result set in the given context"
Does anyone have any idea on what the error is?
Procedure code:
CREATE DEFINER=`redpass_web_urs`#`%` PROCEDURE `ACH_Deposit`(
IN __Account_ID BIGINT,
IN __To_Bank_Account BIGINT,
IN __Amount DECIMAL(10,2),
IN __Currency CHAR(3),
IN __IP_Address VARCHAR(50)
)
COMMENT 'Makes a ACH deposit'
BEGIN
-- Declare Account Parameters
DECLARE _Account_Status INT;
DECLARE __Transaction_ID INT;
DECLARE _Account_Type INT DEFAULT 0;
DECLARE _Fee INT;
SELECT
Account_Status AS _Account_Status,
Account_Type AS _Account_Type
FROM Account_Users
WHERE Account_ID = __Account_ID;
main: BEGIN
-- Step 1, is account active ?
IF _Account_Status <> 1 THEN
-- Account must be active (not restricted, closed etc)
SELECT Response_Code, Description FROM ResponseCodes WHERE Response_Code = 106;
LEAVE main; -- Here we die..
END IF;
-- Step 2, Calculate the FEE (Loading Funds with ACH)
IF _Account_Type = 1 THEN
-- Personal Account
SET _Fee = (SELECT Fee_Template_Personal_1 FROM Fees WHERE Fee_Type_ID = __Fee_Type_ID);
ELSE
-- Business Account
SET _Fee = (SELECT Fee_Template_Business_1 FROM Fees WHERE Fee_Type_ID = __Fee_Type_ID);
END IF;
-- Step 3, Check that Fee is not bigger then the actual amount
IF _Fee > __Amount THEN
SELECT Response_Code, Description FROM ResponseCodes WHERE Response_Code = 108;
LEAVE main; -- Here we die..
END IF;
-- If we come here, we can make the transactions
INSERT INTO Bank_Transaction
(Bank_Account_ID
,Transaction_Type
,Amount
,IP_Address
,Pending)
VALUES
(__To_Bank_Account
,11
,__Amount
,__IP_Address
,1); -- Reserverade pengar
-- Transaction ID
SET __Transaction_ID = (SELECT LAST_INSERT_ID());
-- Deduct the Fee
INSERT INTO Bank_Transaction
(Bank_Account_ID
,Transaction_Type
,Amount
,Fee_Type_ID
,Fee_Transaction_ID)
VALUES
(__To_Bank_Account
,4
,-__Fee
,21
,__Transaction_ID);
END main;
SELECT Response_Code, Description, __Transaction_ID AS Transaction_ID
FROM ResponseCodes
WHERE Response_Code = 1;
END
To retrieve multiple resultsets from the stored procs, you should use a client which supports multiple queries.
If you use PHP, use MySQLi extension and call the procedure using mysqli_multi_query.
MySQL extension is only able to retrieve the first recordset returned by the proc. To be able to use ti, you should set CLIENT_MULTI_RESULTS (decimal 131072) in the parameter $client_flags to mysql_connect