更新存储过程中的表记录并返回该记录的ID

时间:2016-01-26 14:30:56

标签: mysql stored-procedures sql-update mysql-5.6

在2个玩家的Android文字游戏中 -

apps creenshot

游戏数据保存在下表中:

# desc games;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| gid      | int(11)      | NO   | PRI | NULL    | auto_increment |
| created  | int(11)      | NO   |     | NULL    |                |
| player1  | int(11)      | YES  |     | NULL    |                |
| player2  | int(11)      | YES  |     | NULL    |                |
| stamp1   | int(11)      | NO   |     | NULL    |                |
| stamp2   | int(11)      | NO   |     | NULL    |                |
| letters1 | varchar(7)   | NO   |     | NULL    |                |
| letters2 | varchar(7)   | NO   |     | NULL    |                |
| letters  | varchar(116) | NO   |     | NULL    |                |
| board    | varchar(225) | NO   |     | NULL    |                |
| style    | int(11)      | NO   |     | 0       |                |
+----------+--------------+------+-----+---------+----------------+

player1 player2 列会在游戏中保留两个不同的数字ID。

stamp1 stamp2 是最后一次移动的时间戳(最初为0)。

我正在尝试编写一个stored procedure来吸引玩家 uid 并与其他1位玩家一起加入空置游戏,或者从头开始制作新游戏。

一个特例是:如果已经有一个玩家 uid 的新游戏,她还没有进行移动(即 stamp1 为0) ,然后我只返回该游戏的 gid (而不是创建另一款新游戏)。

delimiter $$$

drop procedure if exists find_game;
create procedure find_game(IN uid integer,
                           IN letters1 varchar(7),
                           IN letters2 varchar(7),
                           IN letters varchar(116),
                           OUT gid integer)
begin
        start transaction;

        /* maybe there is a new game already, just waiting for the player's 1st move*/
        select gid into @gid from games where (player1 = uid and stamp1 = 0) or (player2 = uid and stamp2 = 0) limit 1;

        IF found_rows() = 0 THEN
                /* try to find games having just 1 player (with different uid) */
                update games set player2 = uid where player1 != uid and stamp1 > 0 and player2 = null;
                IF row_count() = 0 THEN
                        /* create new game with player1 = uid and stamp1 = 0*/
                        insert into games (created, player1, stamp1, stamp2, letters1, letters2, letters, board, style)
                        values (unix_timestamp(), uid, 0, 0, letters1, letters2, letters, space(225), 1);
                ELSE
                        /* how to find the gid of the updated record? */
                END IF;
        END IF;

        commit;
end
$$$

不幸的是,上面的代码有两个问题。

1)如果我评论除上面第一个选择语句之外的所有内容 - 我在 gid 中得到 null ,而当我在mysql提示它按预期工作:

# select gid from games where (player1 = 1 and stamp1 = 0) or (player2 = 1 and stamp2 = 0);
+-----+
| gid |
+-----+
|   1 |
|   2 |
|   3 |
+-----+

2)请告知,如何在row_count() > 0的上述情况下找到更新游戏的 gid 。或者也许有更好的方法?

更新

我遵循Juan Carlos的建议(谢谢!)并尝试以下代码首先选择然后更新

delimiter $$$

drop procedure if exists find_game;
create procedure find_game(IN uid integer,
                           IN letters1 varchar(7),
                           IN letters2 varchar(7),
                           IN letters varchar(116),
                           OUT gid integer)
begin
        start transaction;

        /* maybe there is a new game already, just waiting for the player's 1st move*/
        select gid into @gid from games
        where (player1 = uid and stamp1 = 0) or (player2 = uid and stamp2 = 0) limit 1;

        IF select found_rows() = 0 THEN
                /* try to find games having just 1 player (with different uid) */
                select gid into @gid from games
                where (player1 != uid and stamp1 > 0 and player2 is null) limit 1;

                IF select found_rows() > 0 THEN
                        update games set player2 = uid where gid = @gid;
                ELSE
                        /* create new game with player1 = uid and stamp1 = 0*/
                        insert into games (created, player1, stamp1, stamp2, letters1, letters2, letters, board, style)
                        values (unix_timestamp(), uid, 0, 0, letters1, letters2, letters, space(225), 1);

                        select last_insert_id() into @gid;
                END IF;
        END IF;

        commit;
end
$$$

不幸的是,我收到了语法错误:

ERROR 1064 (42000): 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 
'select found_rows() = 0 THEN

                select gid into @g' at line 13

1 个答案:

答案 0 :(得分:1)

如果你已经拥有这个,但是如果玩家已经进入了一个全新的游戏,那就找到了。

 select gid into @gid 
 from games 
 where (player1 != uid and stamp1 = 0) 
    or (player2 = uid and stamp2 = 0) limit 1;

为什么不使用类似的东西来更改您的更新,在那里您可以找到空位的游戏。

 select gid into @gid 
 from games 
 where (player1 !=  uid and stamp1 > 0 and player2 is null);

 update games set player2 = uid where gid = @gid 

注意:为什么要搜索stamp1 > 0?您的插入内容会使用stamp1 = 0创建新游戏,您的更新将找不到仅包含1 player

的游戏