如果我有这样的表结构:
CREATE TABLE a (
aid INT AUTO_INCREMENT,
acol1 INT,
acol2 INT,
PRIMARY KEY(aid);
)
CREATE TABLE b (
bid INT AUTO_INCREMENT,
bcol INT,
PRIMARY KEY(bid);
)
并运行声明:
`INSERT IN TO SET acol1 =(SELECT MAX(acol1)+ 1 as newMax FROM WHERE id =?)
在执行查询后,我是否还要检索newMax的值?我在PHP中寻找与last_insert_id()
类似的东西,但在查询中寻找临时值。
显然,我试图在可能的情况下再次查询数据库。
编辑:
实际情况:
CREATE TABLE group (
group_id INT AUTO_INCREMENT,
PRIMARY KEY(group_id)
) ENGINE = MyISAM;
CREATE TABLE item (
group_refid INT, --references group.group_id
group_pos INT, --represents this item's position in its group
text VARCHAR(4096), --data
PRIMARY KEY(group_refid, group_pos)
) ENGINE = MyISAM;
所以问题是,当我向一个组添加一个新项目时,我需要创建它的
group_pos = MAX(group_pos) WHERE group_refid = ?
需要查询类似的内容:
INSERT INTO item (group_refid, group_pos) SET group_refid = 1, group_pos = (SELECT MAX(group_pos) + 1 FROM item WHERE group_refid = 1);
如您所知,此查询不起作用。对于特定的group_id
,可能还没有项目条目的复杂性。
我试图将这一切都整合到一个原子声明中以防止竞争条件。
答案 0 :(得分:1)
您必须运行其他类似的查询
SELECT MAX(acol1) + 1 as newMax FROM a WHERE acol2 = ?
了解更多read this
答案 1 :(得分:1)
我认为你可以做到:
INSERT INTO b
SET bcol = (SELECT @acol := MAX(acol1) + 1 as newMax FROM a WHERE acol2 = ?);
然后,您可以使用变量@acol
来获取所需的值。
编辑:
这是你想要的吗?
INSERT INTO item (group_refid, group_pos)
SELECT 1, MAX(group_pos) + 1
FROM item
WHERE group_refid = 1;
答案 2 :(得分:1)
INSERT INTO item (group_refid,group_pos)
SELECT 1, (
SELECT IFNULL(MAX(group_pos),0) + 1
FROM item
WHERE group_refid=1
);
但是,如果我们明确地谈论 MyISAM表,而不是另一个引擎,那么这将有效:
mysql> CREATE TABLE items (group_refid INT, group_pos INT AUTO_INCREMENT, PRIMARY KEY(group_refid,group_pos)) ENGINE=MyISAM;
Query OK, 0 rows affected (0.12 sec)
mysql> INSERT INTO items (group_refid) VALUES (1),(2),(1),(1),(2),(4),(2),(1);
Query OK, 8 rows affected (0.02 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM items ORDER BY group_refid, group_pos;
+-------------+-----------+
| group_refid | group_pos |
+-------------+-----------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 1 |
| 2 | 2 |
| 2 | 3 |
| 4 | 1 |
+-------------+-----------+
但是,PK中第二列的AUTO_INCREMENT
无法移植到另一个数据库引擎。
答案 3 :(得分:0)
不直接在声明中,没有。您需要一个单独的语句来检索值。
但是,您可以将SELECT中的值“捕获”到用户定义的变量中,然后使用SELECT(在同一个数据库会话中)检索它,如果您需要“知道”从SELECT返回的值
例如:
INSERT INTO b (bcol)
SELECT @bcol := (MAX(a.acol1) + 1) AS newMax
FROM a WHERE a.acol2 = ?)
SELECT @bcol + 0 AS new_bcol
注:
请注意,select中分配的用户定义变量可能会在会话的其他位置进行修改,例如,它可能会被执行定义INSERT目标表的触发器覆盖。
作为边缘情况,不是任何人都会这样做,但也有可能在插入之前可能有一个BEFORE INSERT触发器修改bcol
的值。因此,如果您需要“知道”实际插入的值,那么可以在AFTER INSERT触发器中使用。您可以在该触发器中的用户定义变量中捕获它。
针对a
表运行第二个单独的查询受竞争条件的影响,这是另一个会话插入/更新/删除表a
中的行的小机会窗口,例如第二个查询可能返回与第一个查询不同的值...它可能不是第一次检索的值。当然,除非您处于具有REPEATABLE READ隔离级别的InnoDB事务的上下文中,否则您已实现了一些并发锁定策略。