MySql Function inside stored procedure - mysql

Is that possible to write a function inside MySql stored procedure?
I have set of queries like this.
INSERT INTO party (Description, ShortName)
SELECT CompanyName, NULL FROM tempParentSource;
SET #PartyID = LAST_INSERT_ID();
INSERT INTO partyrole (PartyID,RoleTypeID)
SELECT #PartyID , 5;
SET #ParentSourcePartyRoleID = LAST_INSERT_ID();
-- insert parentSource table
INSERT INTO parentsource (OrgPartyRoleID, CompanyName, ContactNumber, ContactName, ContactEmail, Ext, ContactTelephone)
SELECT #ParentSourcePartyRoleID , CompanyName, ContactPhone, ContactName, ContactEmail, Ext, ContactTelephone FROM tempParentSource;
SET #ParentSourceID = LAST_INSERT_ID();
There are few conditions to check and execute given set of queries. Following are the conditions
IF (#ParentSourceID IS NOT NULL AND #ParentSourcePartyRoleID != #CurOrgPartyID)
ELSEIF (#ParentSourceID IS NULL AND #ParentSourcePartyRoleID IS NOT NULL)
ELSEIF (#ParentSourcePartyRoleID IS NULL AND #CompanyName IS NOT NULL)
Inside of these conditions, i need to execute above given set of queries. Instead of repeating those queries inside each and every condition. If that is possible, how can i write a function and call inside those conditions?

Related

Mysql Using a variable within a case statement

Trying to do something very simple.
Want to Run a SP that checks if one of the arguments is null. If so, store an empty string in a log table, otherwise store the value.
CREATE DEFINER=`root`#`localhost` PROCEDURE `SP_TestVariable`(
Code1 varchar(255) ,
CodeToTest varchar(255)
)
BEGIN
CASE
WHEN CodeToTest IS NULL THEN
set #FinalCode = ' '
ELSE
set #FinalCode = CodeToTest
end
-- Now do the insert into the log table
INSERT INTO `TempLogTable` ( strField1, strField2)
VALUES (Code1 , #FinalCode );
You can reduce all that to a simle query
INSERT INTO `TempLogTable` (strField1, strField2)
SELECT Code1, coalesce(CodeToTest, '')
and for that I would even drop the procedure and just use the query instead.

Error assigning query results to a variable in a stored procedure

I am having issues assigning a variable to a query result and then inserting the value of that variable in a table. The row is inserted into the table but the 'gPayRef' field (which is supposed to house the value of the variable) is null
This is my code:-
SET #eReceipt =
(SELECT DISTINCT `gpayref`
FROM `TRANSACTION`
WHERE `ereceipt` = '12345');
INSERT INTO reversals (gpayref, reversalinitby, reversalinitdate, reason, status)
VALUES (#eReceipt,
reversalinitby,
Now(),
reason,
(SELECT id
FROM `status`
WHERE NAME = 'Reversal pending'));
SELECT Row_count() INTO res;

Update database sortorder column based on array value list

I need to update the sort order column based on the sequence of primary key values I get as array list from ajax call. For example I have 2 coulmns (ID, Sortorder) with values (23,1)(32,2)(21,3)(43,4), now the user from the frontend moves the 3rd row(21,3) above second row(32,2) and I get the ID array sequence as 23, 21, 32, 43 which I have to maintain. From this list, I am trying to update the sororder as per the sequence, so the database table values should look as (23,1)(32,3)(21,2)(43,4). Could you help me to get this DB update statement.
Attached the print screen for better understanding:
Java logic I have, trying to find an update sql statement to loop from an array list. I have ~1000 rows in my table and with my logic, this would trigger 1000 update queries, I don't think this is efficient. Trying to find an alternate efficient way.
Connection conn = null;
PreparedStatement pstmt = null;
conn = getConnection();
String query = "update Sortordertable set sortorder = ? where Id = ? ";
pstmt = conn.prepareStatement(query); // create a statement
String str[]=String.valueOf(s.getRecordId()).split(";");//id1;id;id3;.... list I get from ajax call
for(int i=0;i<str.length();i++)
{
pstmt.setId(1,i++); //set sortorder value as 1, 2, 3..
pstmt.setInt(2, str[i]); // In this line I want to use my array-list to update my table.
pstmt.executeUpdate(); // execute update statement
}
For the specific use case you have showed, you could use the following query, which would update only the rows with id=32 or id=23.
UPDATE t1 SET
sortorder = CASE WHEN id = 32 THEN 3 ELSE 2 END
WHERE id IN (32, 21);
This could be adapted for multiple updates if you don't update the database after each operation. but will grow with the number of operations made by the user before the update is triggered.
Edit to address comment:
If, as in the example given in your comment, you want to move the row with order 4 to the first row, you can use the following:
UPDATE t1 SET
sortorder = CASE WHEN sortorder = 4 THEN 1 ELSE sortorder + 1 END
WHERE sortorder <= 4;
I've added a where clause in that last query to illustrate that you can easily adapt this to different use case.
Here's what you can do:
DELIMITER $$
CREATE PROCEDURE `sp_update_positions`(
IN `p_positions` VARCHAR(255)
)
BEGIN
SET #positions = REPLACE(p_positions, ',', '),(');
SET #positions = CONCAT('(', #positions, ')');
DROP TEMPORARY TABLE IF EXISTS tmpPositions;
CREATE TEMPORARY TABLE tmpPositions(
`position` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`order_id` int(10) unsigned NOT NULL
);
SET #insertString = CONCAT('INSERT INTO tmpPositions (`order_id`) VALUES ', #positions);
PREPARE insertStatement FROM #insertString;
EXECUTE insertStatement;
DEALLOCATE PREPARE insertStatement;
UPDATE orders
INNER JOIN tmpPositions ON order_id = orders.id
SET orders.Sortorder = tmpPositions.position;
SELECT ROW_COUNT() AS rowCount;
END$$
DELIMITER ;
Then you call it like this:
CALL sp_update_positions('24,23,21,22');

Parameterized nested query

I'm trying to parameterize the following insert with a nested select.
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), "param1", str2 FROM table2 WHERE key = "param2");
I'd like something like
INSERT IGNORE INTO table1 (creation_timestamp, str1, str2)
(SELECT now(), ?, str2 FROM table2 WHERE key = ?)
VALUES ("param1", "param2");
Anyone know how I can accomplish something like this?
Not exactly the same, but very similar.
You can use prepared statements:
http://dev.mysql.com/doc/refman/5.7/en/sql-syntax-prepared-statements.html
Example:
PREPARE soExample
FROM 'INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, ?, (SELECT name
FROM customers
WHERE id = ?
LIMIT 1))';
SET #uname = "someUserNameForTheExample";
SET #id = "1";
EXECUTE soExample USING #uname, #id;
Or you can user procedure or/and functions as well
FUNCTION
DROP FUNCTION IF EXISTS insertExample$$
CREATE FUNCTION insertExample(userNameVar VARCHAR(255), uID INT(11)) RETURNS BOOLEAN
BEGIN
INSERT
INTO usr (id, username, profile_pic)
VALUES (NULL, userNameVar, (SELECT name
FROM customers
WHERE id = uID
LIMIT 1));
IF ROW_COUNT() > 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
END$$
FUNCTION USE
SELECT insertExample("SomeUsername" 2);
Perhaps you should start by reading https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html. As Mysql Functions enables parameterized input for pre-build queries.

mysql update column then select updated value

I have a table like this
tbl_user
id
user_id
amount
first i want to update a row based on id
$amount = 123; // dyanamic value
$sql = "UPDATE tbl_user SET amount=amount-'$amount' WHERE id='$id' LIMIT 1 ";
now i want to get updated value of amount column i have applied this sql
$sql = "SELECT amount FROM tbl_user WHERE id='$id' LIMIT 1 ";
my question is can i combine both of above sql or any single query to achieve above task?
The best you could imitate is to use two lines of queries, probably using a variable like:
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
The best you could do then is to create a Stored Procedure like:
DELIMITER //
CREATE PROCEDURE `return_amount` ()
BEGIN
UPDATE tbl_user SET
amount = #amount := amount-'$amount'
WHERE id='$id' LIMIT 1;
SELECT #amount;
END //
And then call Stored Procedure in your PHP.
Note: PostgreSQL has this kind of option using RETURNING statement that would look like this:
UPDATE tbl_user SET amount=amount-'$amount'
WHERE id='$id' LIMIT 1
RETURNING amount
See here
A function can do this easily. It sounds like you want to limit how many times your code connects to the database. With a stored function or procedure, you are only making one connection. Yes, the stored function has two queries inside it (update then select), but these are executed on the server side without stopping to do round trips to the client.
http://sqlfiddle.com/#!2/0e6a09/1/0
Here's my skeleton of your table:
CREATE TABLE tbl_user (
id VARCHAR(100) PRIMARY KEY,
user_id VARCHAR(100),
amount DECIMAL(17,4) );
INSERT INTO tbl_user VALUES ('1', 'John', '100.00');
And the proposed function:
CREATE FUNCTION incrementAmount
(p_id VARCHAR(100), p_amount DECIMAL(17,4))
RETURNS DECIMAL(17,4)
BEGIN
UPDATE tbl_user
SET amount = amount + p_amount
WHERE id = p_id;
RETURN (SELECT amount FROM tbl_user WHERE id = p_id);
END
//
Then you just run one query, a SELECT on the function you just created:
SELECT incrementAmount('1', 5.00)
The query result is:
105
It is not possible with a single query, but you can combine multiple commands into a script and execute them with a single request to the database server.
Run this script:
"UPDATE tbl_user SET amount=amount-'$amount' WHERE id='".$id."';SELECT amount FROM tbl_user WHERE id='".$id."'; "
Also, you might want to check whether $id is a number, as I do not see a protection against SQL injection inside your code. SQL injection is a serious threat, you would do better to prepare and protect yourself against it.
We can also use:
UPDATE tbl_user SET id = LAST_INSERT_ID(id), amount = 2.4,user_id=4 WHERE id = 123;
// SELECT
$id =SELECT LAST_INSERT_ID();
SELECT amount,user_id FROM tbl_user WHERE id = $id LIMIT 1
Here would be the procedure
CREATE PROCEDURE UpdateAndSelect
(
#amount MONEY,
#id INT
)
AS
BEGIN
UPDATE tbl_user
SET amount = #amount
WHERE id = #id
LIMIT 1
SELECT amount
FROM tbl_user
WHERE id = #id
LIMIT 1
END
GO
You would call this stored procedure by setting your variables (#amoutn and #id) and then calling:
exec UpdateAndSelect
Hope this helps solve your problem