How to Pass Variable into a MySQL Stored Procedure from PHP - php

I have the following stored procedure:
proc_main:begin
declare done tinyint unsigned default 0;
declare dpth smallint unsigned default 0;
create temporary table hier(
AGTREFERRER int unsigned,
AGTNO int unsigned,
depth smallint unsigned default 0
)engine = memory;
insert into hier values (p_agent_id, p_agent_id, dpth);
/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */
create temporary table tmp engine=memory select * from hier;
while done <> 1 do
if exists( select 1 from agents a inner join hier on a.AGTREFERRER = hier.AGTNO and hier.depth = dpth) then
insert into hier
select a.AGTREFERRER, a.AGTNO, dpth + 1 from agents a
inner join tmp on a.AGTREFERRER = tmp.AGTNO and tmp.depth = dpth;
set dpth = dpth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = dpth;
else
set done = 1;
end if;
end while;
select
a.AGTNO,
a.AGTLNAME as agent_name,
if(a.AGTNO = b.AGTNO, null, b.AGTNO) as AGTREFERRER,
if(a.AGTNO = b.AGTNO, null, b.AGTLNAME) as parent_agent_name,
hier.depth,
a.AGTCOMMLVL
from
hier
inner join agents a on hier.AGTNO = a.AGTNO
inner join agents b on hier.AGTREFERRER = b.AGTNO
order by
-- dont want to sort by depth but by commission instead - i think ??
-- hier.depth, hier.agent_id;
a.AGTCOMMLVL desc;
drop temporary table if exists hier;
drop temporary table if exists tmp;
end proc_main
While the function does its job well - it only currently allows sorting via AGTCOMMLVL descending order. The stored procedure's purpose is to match a memberID with their parentID and associated COMMLVL. Once paired appropriately,I use the memberID in a second query to return information about that particular member.
I would like to be able to sort by any number of filters but have the following problems:
I can't seem to find a way to pass a variable into the stored procedure altering its sorting by field.
Even if I could - the sort may actually only contain data from the second query (such as first name, last name, etc)
Running a sort in the second query does nothing even though syntax is correct - it always falls back to the stored procedure's sort.
any ideas?
EDIT
My php uses mysqli with code:
$sql = sprintf("call agent_hier2(%d)", $agtid);
$resulta = $mysqli->query($sql, MYSQLI_STORE_RESULT) or exit(mysqli_error($mysqli));

If you want to sort by input parameter of the stored procedure, you need to use Prepared staments
For example,
DELIMITER //
CREATE PROCEDURE `test1`(IN field_name VARCHAR(40) )
BEGIN
SET #qr = CONCAT ("SELECT * FROM table_name ORDER BY ", field_name);
PREPARE stmt FROM #qr;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //

$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";

This also works in Mysql 5.6
DELIMITER //
CREATE PROCEDURE `test1`(IN field_name VARCHAR(40) )
BEGIN
"SELECT * FROM table_name ORDER BY ", field_name);
END //

Related

How do I CALL mysql TEMPORARY TABLE from CodeIgniter?

I have written a stored procedure in mysql which will create a TEMPORARY TABLE, I want to access the data of TEMPORARY TABLE using Codeigniter.But when I call "$this->db->query()" it returns empty data.
$data=array();
$call_procedure = "CALL sp_Stock()";
$query = $this->db->query($call_procedure);
$sql="SELECT * FROM StockTable";
$query1 = $this->db->query($sql);
I have changed my way to show the data. And I do changes it on stored procedure.
DELIMITER $$
CREATE PROCEDURE sp_Stock()
BEGIN
DECLARE cursor_finish INTEGER DEFAULT 0;
DECLARE m_numofpurchaseBag DECIMAL(10,2)DEFAULT 0;
DECLARE m_purchasedKg DECIMAL(10,2)DEFAULT 0;
DECLARE m_purBagDtlId INTEGER DEFAULT 0;
DECLARE stockCursor CURSOR FOR
SELECT purchase_bag_details.`actual_bags`,
(purchase_bag_details.`net`*purchase_bag_details.`actual_bags`) AS PurchasedKg,
purchase_bag_details.`id` AS PurchaseBagDtlId
FROM
purchase_invoice_detail
INNER JOIN
purchase_bag_details
ON purchase_invoice_detail.`id`= purchase_bag_details.`purchasedtlid`
INNER JOIN
`do_to_transporter`
ON purchase_invoice_detail.`id` = do_to_transporter.`purchase_inv_dtlid`
WHERE purchase_invoice_detail.`teagroup_master_id`=6
AND purchase_invoice_detail.`id`=1481
AND do_to_transporter.`in_Stock`='Y';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET cursor_finish = 1;
DROP TEMPORARY TABLE IF EXISTS StockTable;
#temptable creation
CREATE TEMPORARY TABLE IF NOT EXISTS StockTable
(
purchaseBagDtlId INT,
purchasedBag NUMERIC(10,2),
purchasedKg NUMERIC(10,2),
blendedBag NUMERIC(10,2),
blendedKg NUMERIC(10,2),
stockBag NUMERIC(10,2),
stockKg NUMERIC(10,2)
);
#temptable creation
OPEN stockCursor ;
get_stock : LOOP
FETCH stockCursor INTO m_numofpurchaseBag,m_purchasedKg,m_purBagDtlId;
IF cursor_finish = 1 THEN
LEAVE get_stock;
END IF;
/*SELECT m_numofpurchaseBag,m_purchasedKg,m_purBagDtlId; */
/* Blending bag query*/
SET #m_numberofBlndBag:=0;
SET #m_BlndKg:=0;
/* Blend bag*/
SELECT #m_numberofBlndBag:=SUM(blending_details.`number_of_blended_bag`) AS belendedBag INTO #m_numberofBlndBag
FROM blending_details
WHERE blending_details.`purchasebag_id`= m_purBagDtlId
GROUP BY
blending_details.`purchasebag_id`;
#Blend Bag
#Blend Kgs
SELECT #m_BlndKg:=SUM(blending_details.`qty_of_bag` * blending_details.`number_of_blended_bag`) AS blendkg INTO #m_BlndKg
FROM blending_details
WHERE blending_details.`purchasebag_id`= m_purBagDtlId
GROUP BY
blending_details.`purchasebag_id`;
SET #m_StockBag:=(m_numofpurchaseBag - #m_numberofBlndBag);
SET #m_StockKg:=(m_purchasedKg - #m_BlndKg);
INSERT INTO StockTable
(
purchaseBagDtlId ,
purchasedBag ,
purchasedKg ,
blendedBag ,
blendedKg ,
stockBag ,
stockKg
)VALUES(m_purBagDtlId,m_numofpurchaseBag,m_purchasedKg,#m_numberofBlndBag,#m_BlndKg,#m_StockBag,#m_StockKg);
END LOOP get_stock;
CLOSE stockCursor;
SELECT * FROM StockTable;
#DROP TABLE StockTable;
END$$
DELIMITER ;
#CALL sp_Stock();
Anywhere I am using a temp table I am executing this before the temp table is created:
$this->db->query('DROP TABLE IF EXISTS StockTable');
I seem to remember reading someone having the same problem as you and for some reason you have to execute the above first.
So try:
$data=array();
$call_procedure = "CALL sp_Stock()";
$this->db->query('DROP TABLE IF EXISTS StockTable');
$query = $this->db->query($call_procedure);
$sql="SELECT * FROM StockTable";
$query1 = $this->db->query($sql);

Creating stored procedure for multiple insert and alter table queries

$link->query("DROP TABLE IF EXISTS table2");
$link->query("CREATE TABLE table2 (newcol BIGINT UNSIGNED PRIMARY KEY)");
$result=$link->query("select col1 from table1");
while($data=$result->fetch_array(MYSQL_ASSOC))
{
$link->query("insert into table2 (newcol) values($data['col1']);
$link->query(""ALTER TABLE table2 ADD `".$data['col1']."` BIGINT DEFAULT 0"");
}
What Iam trying to do is
Create a table "table2" with one column "newcol".
select all the values of "col1" from "table1" And
for each value of col1 from table1
-insert the value into "newcol" of table2 And
-add a column named (value from col1 of table 1) into "table2"
The above code looks very neat and efficient in php , but the problem is it takes some amount of time .So I think its better to convert these into MySQL Stored procedure .Since I'm new to stored procedures , very much confused .Please help me guys.
Of course, I couldn't test it, but it is compiling fine on on my computer.
DELIMITER //
CREATE PROCEDURE `myProcedure` ()
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT UNSIGNED DEFAULT 0;
/* the cursor here is like your PDOStatement
* it is used to fetch data */
DEClARE _myReader CURSOR FOR
SELECT `col1` FROM `table1`;
/* it is not very elegant, but we need to throw an exception
* to break the loop */
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `table2`;
CREATE TABLE `table2` (
`newcol` BIGINT UNSIGNED PRIMARY KEY
);
/* you open your PDOStatement */
OPEN _myReader;
/* myLoop is like a GOTO*/
myLoop: LOOP
/* $result->fetch_array(MYSQL_ASSOC)*/
FETCH _myReader INTO _myField;
/* if the no data exception had been thrown,
* goto the end of the loop */
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `table2` (newcol) VALUES (_myField);
ALTER TABLE `table2` ADD `_myField` BIGINT DEFAULT 0;
END LOOP myLoop;
/* close your PDO object */
CLOSE _myReader;
END //
Jonathan Parent Lévesque helped me a lot in figuring out how the looping inside stored procedures work and to get the overall structure for the stored procedure equivalent to the php code described in the question above.
Thanks Jonathan Parent Lévesque
But in his code Adding column name using a variable didn't work as expected.
Finally I figured it out
BEGIN
DECLARE _done BOOLEAN DEFAULT FALSE;
DECLARE _myField BIGINT DEFAULT 0;
DEClARE _myReader CURSOR FOR
SELECT id FROM `tags`;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET _done = TRUE;
DROP TABLE IF EXISTS `tag_similarity`;
CREATE TABLE `tag_similarity` (
`tag` BIGINT UNSIGNED PRIMARY KEY
);
OPEN _myReader;
myLoop: LOOP
FETCH _myReader INTO _myField;
IF _done = 1 THEN
LEAVE myLoop;
END IF;
INSERT INTO `tag_similarity` (tag) VALUES (_myField);
SET #sql = CONCAT('ALTER TABLE tag_similarity ADD `',_myfield,'` BIGINT DEFAULT 0');
PREPARE stmt FROM #sql;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END LOOP myLoop;
CLOSE _myReader;
END

Return Select * from PHP PDO Stored Procedure In MS SQL

For future users: The bottom of this question contains the corrected working code.
I know Select * is not the best, but in this example, I am trying to call a stored procedure from php and return the ENTIRE result set so I can loop through the array in my code.
Here is my current stored procedure:
USE [hanoncs_AskMe]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET NOCOUNT ON;
GO
CREATE PROCEDURE [hanoncs_hanoncs].[CommentsTemp]
#QuestionID INT
AS
BEGIN
BEGIN TRANSACTION
IF Object_id('#viewquestioncomments', 'U') IS NOT NULL DROP TABLE #viewquestioncomments;
CREATE TABLE #viewquestioncomments
(
commentid INT DEFAULT ((0)),
userid INT DEFAULT ((0)),
comment VARCHAR(max) DEFAULT '',
datemodified SMALLDATETIME,
username NVARCHAR(200) DEFAULT '',
points INT DEFAULT ((0))
);
INSERT INTO #viewquestioncomments
(
commentid,
userid,
comment,
datemodified
)
SELECT id,
userid,
comment,
datemodified
FROM hanoncs_askme.hanoncs_hanoncs.comments
WHERE postid=1
AND status=1;
UPDATE #viewquestioncomments
SET username = m.username
FROM #viewquestioncomments c
LEFT JOIN hanoncs_securelogin.hanoncs_hanoncs.members m
ON m.id = c.userid;
UPDATE #viewquestioncomments
SET points =
(
SELECT Count(*)
FROM hanoncs_askme.hanoncs_hanoncs.commentvotes
WHERE postid=c.commentid)
FROM #viewquestioncomments c;
SELECT *
FROM #viewquestioncomments;
IF ##ERROR != 0
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
END
In MS SQL Management Studio, this returns the temp table like I want:
EXEC [hanoncs_hanoncs].[CommentsTemp] #QuestionID = 1
I am calling it in php with:
$stmt = $PDO->prepare('EXEC [hanoncs_hanoncs].[CommentsTemp] #QuestionID = ?');
$stmt->bindParam(1, $QuestionID, PDO::PARAM_INT);
$stmt->execute();
$rows6 = $stmt->fetch(PDO::FETCH_BOTH);
The error I get is:
PDOException SQLSTATE[IMSSP]: The active result for the query contains no fields.
/
EDIT:For future users!!! The working code is below.
Stored Procedure:
USE [hanoncs_AskMe]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [hanoncs_hanoncs].[CommentsTemp]
#QuestionID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
IF Object_id('#viewquestioncomments', 'U') IS NOT NULL DROP TABLE #viewquestioncomments;
CREATE TABLE #viewquestioncomments
(
CommentID INT DEFAULT ((0)),
UserID INT DEFAULT ((0)),
Comment VARCHAR(max) DEFAULT '',
DateModified SMALLDATETIME,
UserName NVARCHAR(200) DEFAULT '',
Points INT DEFAULT ((0)),
Avatar nvarchar(200) DEFAULT ''
);
INSERT INTO #viewquestioncomments
(
commentid,
userid,
comment,
datemodified
)
SELECT id,
userid,
comment,
datemodified
FROM hanoncs_askme.hanoncs_hanoncs.comments
WHERE postid=1
AND status=1;
UPDATE #viewquestioncomments
SET username = m.username , Avatar = m.avatar
FROM #viewquestioncomments c
LEFT JOIN hanoncs_securelogin.hanoncs_hanoncs.members m
ON m.id = c.userid;
UPDATE #viewquestioncomments
SET points =
(
SELECT Count(*)
FROM hanoncs_askme.hanoncs_hanoncs.commentvotes
WHERE postid=c.commentid)
FROM #viewquestioncomments c;
SELECT *
FROM #viewquestioncomments;
IF ##ERROR != 0
ROLLBACK TRANSACTION
ELSE
COMMIT TRANSACTION
END
PHP:
$stmt = $PDO->prepare('EXEC [hanoncs_hanoncs].[CommentsTemp] #QuestionID = ?');
$stmt->bindParam(1, $QuestionID, PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Try adding SET NOCOUNT ON; inside the stored procedure (not above where you are creating the procedure).
Add it after the AS BEGIN and before the BEGIN TRANSACTION;
Like so:
CREATE PROCEDURE [hanoncs_hanoncs].[CommentsTemp]
#QuestionID INT
AS BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
From what it looks like to me, your result set will contain the row counts of affected rows first, then the actual data you want back.

TSQL: passing ids from select clause to stored procedure

I have a procedure called SELECT_DESCRIPTION that receives an id and returns a Description field I need to show in my page.
Now I want to create a new procedure that having a number of ids coming from a select clause like this:
SELECT id FROM MYTABLE
Can pass it to the SELECT_DESCRIPTION procedure so I can have the same number of descriptions
If I was using php I would be doing something like this:
$sql=”SELECT id FROM MYTABLE”;
$result = mysql_query($sql) //using mysql to make the example faster but TSQL is what I use
or die(mysql_error());
while($row = mysql_fetch_array( $result )) {
$newSql = "EXEC SELECT_DESCRIPTION #id = '$row[‘id’]'";
//do whatever with $newSql
}
But I need to use a procedure. Is is possible to do it? How can I do it?
Thanks a ton!
So you're wanting to do all of this in TSQL? Something like this would do it:
DECLARE #tmp TABLE (tmpID INT IDENTITY, tblID INT)
DECLARE #RecordCount INT,
#LoopCount INT,
#ID INT
INSERT INTO #tmp SELECT id FROM MYTABLE
SELECT #RecordCount = COUNT(*) FROM #tmp
SET #LoopCount = 1
WHILE #LoopCount <= #RecordCount
BEGIN
SELECT #ID = tblID FROM #tmp WHERE tmpID = #LoopCount
EXEC SELECT_DESCRIPTION #ID
SELECT #LoopCount = #LoopCount + 1
END
The #tmp table has an identity column that insures whatever data you're running the loop on has consecutive row numbers (1, 2, 3, 4, etc).

Show item of the day

I am looking to create a function that gets me a random item from a mySQL table, but let's me keep the returned as the "item of the day". In other words, the item that was "the item of the day" yesterday should not be shown again until all other items have been shown as item of the day.
Any suggestions on how to do this in an elegant way?
Thanks
Add a bool column "UsedAsItemOfTheDay" set to false (0). Update to true when item is picked. Exclude already used items from the picking process.
SELECT * FROM `table`
WHERE UsedAsItemOfTheDay = 0
ORDER BY RAND() LIMIT 1;
(Note: this is not the fastest way to return a random row in MySql; it will be slow on huge tables)
See also: quick selection of a random row from a large table in mysql
SELECT <fields> FROM <table> WHERE <some logic to exclude already used> ORDER BY RAND() LIMIT 1 will get you a random row from the table.
Add a column to store whether the item has been used:
ALTER TABLE your_table ADD COLUMN isused BOOL DEFAULT 0;
Get a random item of the day:
SELECT t.*
FROM your_table t
WHERE t.isused = 0
ORDER BY RAND()
LIMIT 1
Now update that record so it can't be used in the future:
UPDATE your_table
SET isused = 1
WHERE id = id_from_select_random_statement
People who "know" SQL will look for declarative solutions and will shun procedural code. Flagging rows is a "smell" for procedural code.
Is the set of Items static (never changes) or stable (rarely changes)? If yes, it would be easier to do a one-off exercise of generating a lookup table of values from now until the end of time, rather than scheduling a proc to running daily to look for unused flags and update the flag for today and clear all flags if all have been used etc.
Create a table of sequential dates between today and a far future date representing the lifetime of your application (you could consider omitting non-business days, of course). Add a column(s) referencing the key in you Items table (ensure you opt for ON DELETE NO ACTION referential action just in case those Items prove not to be static!) Then randomly assign the whole set of Items one per day until each has been used once. Repeat again for the whole set of Items until the table is full. You could easily generate this data using a spreadsheet and import it (or pure SQL if you are hardcore ;)
Quick example using Standard SQL:
Say there are only five Items in the set:
CREATE TABLE Items
(
item_ID INTEGER NOT NULL UNIQUE
);
INSERT INTO Items (item_ID)
VALUES (1),
(2),
(3),
(4),
(5);
You lookup table would be as simple as this:
CREATE TABLE ItemsOfTheDay
(
cal_date DATE NOT NULL UNIQUE,
item_ID INTEGER NOT NULL
REFERENCES Items (item_ID)
ON DELETE NO ACTION
ON UPDATE CASCADE
);
Starting with today, add the whole set of Items in random order:
INSERT INTO Items (item_ID)
VALUES ('2010-07-13', 2),
('2010-07-14', 4),
('2010-07-15', 5),
('2010-07-16', 1),
('2010-07-17', 3);
Then, starting with the most recent unfilled date, add the whole set of Items in (hopefully a different) random order:
INSERT INTO Items (item_ID)
VALUES ('2010-07-18', 1),
('2010-07-19', 3),
('2010-07-20', 4),
('2010-07-21', 5),
('2010-07-22', 2);
...and again...
INSERT INTO Items (item_ID)
VALUES ('2010-07-23', 2),
('2010-07-24', 3),
('2010-07-25', 5),
('2010-07-26', 1),
('2010-07-27', 4);
..and so on until the table is full.
Then it would then simply be a case of looking up today's date in the lookup table as and when required.
If the set of Items changes then the lookup table would obviously need to be regenerated, so you need to balance out the simplicity of design against the need for manual maintenance.
If you have fixed items you can add column
ALTER TABLE your_table ADD COLUMN item_day INT DEFAULT 0;
then selecting item use
WHERE item_day = DATE_FORMAT('%j')
If you get empty result then you can format new list of day items:
<?php
$qry = " UPDATE your_table SET item_day = 0";
$db->execute($qry);
// You only need 355 item to set as item of the day
for($i = 0; $i < 355; $i++) {
$qry = "UPDATE your_table SET item_day = ".($i+1)." WHERE item_day = 0 ORDER BY RAND() LIMIT 1";
$rs = $db->execute($qry);
// If no items left stop update
if (!$rs) { break; }
}
?>
Here's a stored procedure which selects a random row without using ORDER BY RAND(), and which resets the used flag once all items have been used:
DELIMITER //
DROP PROCEDURE IF EXISTS random_iotd//
CREATE PROCEDURE random_iotd()
BEGIN
# Reset used flag if all the rows have been used.
SELECT COUNT(*) INTO #used FROM iotd WHERE used = 1;
SELECT COUNT(*) INTO #rows FROM iotd;
IF (#used = #rows) THEN
UPDATE iotd SET used = 0;
END IF;
# Select a random number between 1 and the number of unused rows.
SELECT FLOOR(RAND() * (#rows - #used)) INTO #rand;
# Select the id of the row at position #rand.
PREPARE stmt FROM 'SELECT id INTO #id FROM iotd WHERE used = 0 LIMIT ?,1';
EXECUTE stmt USING #rand;
# Select the row where id = #id.
PREPARE stmt FROM 'SELECT id, item FROM iotd WHERE id = ?';
EXECUTE stmt USING #id;
# Update the row where id = #id.
PREPARE stmt FROM 'UPDATE iotd SET used = 1 WHERE id = ?';
EXECUTE stmt USING #id;
DEALLOCATE PREPARE stmt;
END;
//
DELIMITER ;
To use:
CALL random_iotd();
The procedure assumes a table structure like this:
CREATE TABLE `iotd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(255) NOT NULL,
`used` BOOLEAN NOT NULL DEFAULT 0,
INDEX `used` (`used`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Here's one way to get the result from PHP (to keep things simple, error checking has been removed):
$mysqli = new mysqli('localhost', 'root', 'password', 'database');
$stmt = $mysqli->prepare('CALL random_iotd()');
$stmt->execute();
$stmt->bind_result($id, $item);
$stmt->fetch();
echo "$id, $item\n";
// 4, Item 4
UPADATE
This version should return the same result repeatedly on a given date. I've not really had time to test this, so be sure to do some testing of your own...
DELIMITER //
DROP PROCEDURE IF EXISTS random_iotd//
CREATE PROCEDURE random_iotd()
BEGIN
# Get today's item.
SET #id := NULL;
SELECT id INTO #id FROM iotd WHERE ts = CURRENT_DATE();
IF ISNULL(#id) THEN
# Reset used flag if all the rows have been used.
SELECT COUNT(*) INTO #used FROM iotd WHERE used = 1;
SELECT COUNT(*) INTO #rows FROM iotd;
IF (#used = #rows) THEN
UPDATE iotd SET used = 0;
END IF;
# Select a random number between 1 and the number of unused rows.
SELECT FLOOR(RAND() * (#rows - #used)) INTO #rand;
# Select the id of the row at position #rand.
PREPARE stmt FROM 'SELECT id INTO #id FROM iotd WHERE used = 0 LIMIT ?,1';
EXECUTE stmt USING #rand;
# Update the row where id = #id.
PREPARE stmt FROM 'UPDATE iotd SET used = 1, ts = CURRENT_DATE() WHERE id = ?';
EXECUTE stmt USING #id;
END IF;
# Select the row where id = #id.
PREPARE stmt FROM 'SELECT id, item FROM iotd WHERE id = ?';
EXECUTE stmt USING #id;
DEALLOCATE PREPARE stmt;
END;
//
DELIMITER ;
And the table structure:
CREATE TABLE `iotd` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item` varchar(255) NOT NULL,
`used` BOOLEAN NOT NULL DEFAULT 0,
`ts` DATE DEFAULT 0,
INDEX `used` (`used`),
INDEX `ts` (`ts`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Why don't you use sequence?
Sequence serves your purpose easily...

Categories