我有一张表来存储联系人。
我想获取添加user_id为{some number}的列的最大值,并将其设置为当前插入记录的相同列值。
我正在使用准备好的陈述:
pg_prepare($db, "add", 'INSERT INTO '.CONTACTS.' (c_user_serial,c_name,c_company,c_email) VALUES ($1, $2, $3, $4)');
$insert_co = pg_execute($db, "add", array({(MAX OF c_user_serial where c_user_id = 1234) + 1 increment },$name,$company,$email));
c_user_id
是添加此联系人的用户的ID,还有另一列作为索引(id
),这是一个常见的serial
列,每列增加c_user_serial
{1}}是每个用户递增的序列号。我们假设一位用户添加了一个联系人,因此它是1
。在其他用户添加了多个联系人之后,当该用户添加他的第二个联系人时,我希望此列存储2
,因此自动增加一列,但应该按用户增加。
不确定如何在此处使用内部查询来获取列的最大值,并使用当前插入的递增值。
答案 0 :(得分:1)
此查询可以满足您的要求:
INSERT INTO contacts (c_user_serial, c_user_id, c_name, c_company, c_email)
SELECT max(c_user_serial) + 1, $1, $2, $3, $4
FROM tbl
WHERE c_user_id = $1;
您的原始忘记插入user_id
本身,这是必需的。我加了它。
然而,这带来了几个主要问题:
当前“最大”可以是并发交易 之间 竞争条件的主题,并且不可靠。 (虽然serial
对于并发访问是安全的。)
如果找不到c_user = $1
的行,则插入 nothing 。可能是也可能不是你想要的。
如果max(c_user_serial)
返回NULL,则为c_user_id
插入另一个NULL值
如果c_user_id
被定义为NOT NULL,则不会发生这种情况。
要避免问题2.和3.而是以每个新用户的1
开头:
INSERT INTO contacts (c_user_serial, c_user_id, c_name, c_company, c_email)
VALUES (COALESCE((SELECT max(c_user_serial) + 1 FROM tbl WHERE c_user_id = $1), 1)
, $1, $2, $3, $4)
此处“no row”转换为NULL,在这种情况下,COALESCE
默认为1
。
一切都放在一起,简单的解决方案是:
pg_prepare($db, "add"
, 'INSERT INTO ' . CONTACTS . ' (c_user_serial, c_user_id, c_name, c_company, c_email)
VALUES (COALESCE((SELECT max(c_user_serial) + 1 FROM tbl WHERE c_user_id = $1), 1)
, $1, $2, $3, $4)');
$insert_co = pg_execute($db, "add", array($user_id,$name,$company,$email));
确保CONTACTS
拥有正确转义的表名,或者您对 SQL注入持开放态度。
如果您正在寻找无间隙的序列,您必须以某种方式处理UPDATE
和DELETE
,这将不可避免地笼罩您的序列时间,这也是原因之一,为什么整个想法不那么好。
另一个更重要的原因是我提到的竞争条件。它有没有便宜和优雅的解决方案。 (有解决方案,但或多或少......)
如果可能的话,坚持所有行的一个普通serial
列。在检索数据时,您始终可以从1开始为每个用户附加数字: