我创建了一个表
CREATE TABLE `pledge` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`user` VARCHAR(45) NOT NULL,
`location` VARCHAR(45) NOT NULL,
`category` VARCHAR(45) NOT NULL,
`amount` DOUBLE NULL, NOT NULL,
`p_created` TIMESTAMP NOT NULL,
PRIMARY KEY (`ID`));
我为用户,位置和类别添加了唯一键作为index2。
我想
INSERT a new record, if amount is not zero
UPDATE an existing record, if key (column user, location, category) exists
DELETE a record, if key (column user, location, category) exists AND amount is now zero
try {
$conec = new Connection();
$con = $conec->Open();
$p_created = date("Y-m-d H:i:s");
$sql = "INSERT INTO `pledge`(
`user`,
`location`,
`category`,
`amount`,
`p_created`)
VALUES (
:user,
:location,
:category,
:amount,
:p_created)";
$pre = $con->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
if ($pre->execute(array(
':user' => $user,
':location' => $location,
':category' => $category,
':amount' => $amount,
':p_created' => $p_created,
))) {
// echo "Successful";
}
} catch (PDOException $ex) {
echo $ex->getMessage();
}
} // try
我发现我可以使用“ ON DUPLICATE KEY UPDATE col3 ='alpha';”之类的东西,但是不知道上面的php代码中的用法。 由于存在这种情况,如果数量为零,也有可能删除而不是更新。
更新:
谢谢您的提示。不知何故,我仍然会犯错误。我尝试了很多方法,但是...
首先,我不得不更换桌子。我删除了主键ID,并添加了一个新的主键,其中包含用户,位置,类别列。
为简化我的原始问题,我仅更新了一列,但实际上更新了两列。
有了这些更改,我能够按预期在命令行(工作台)上进行插入/更新:
插入pledge
(user
,location
,category
,mypercent
,mybalance
,p_created
值('5cdae45bdb5c5','Linz','A14',50、300,'2019-05-21 11:12:22')
重复键更新mypercent
= 20,mybalance
= 53;
按预期工作。第一次将其插入mypercent = 50和mybalance = 300,第二次我尝试使用完全相同的命令,则将记录更新为mypercent = 20和mybalance = 53
但是,我无法在我的PHP程序中使用此语法。这是最新的尝试:
try {
$conec = new Connection();
$con = $conec->Open();
$p_created = date("Y-m-d H:i:s");
$sql = "INSERT INTO `pledge`(
`user`,
`location`,
`category`,
`mypercent`,
`mybalance`,
`p_created`)
VALUES (
:user,
:location,
:category,
:mypercent,
:mybalance,
:p_created)
ON DUPLICATE KEY UPDATE (`mypercent` = $percent[0], `mybalance` = $balance[0])
";
// worked on command line: UPDATE `pledge` SET `mypercent`='10',`mybalance`='10' WHERE `user`='5ce3770041037' and `location`='Linz' and`category`='A14';
// ON DUPLICATE KEY UPDATE `p_mypercent`=20, `mybalance` = 53;
$pre = $con->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
if ($pre->execute(array(
':user' => $user,
':location' => $locationid,
':category' => $category,
':mypercent' => $percent[0],
':mybalance' => $balance[0],
':p_created' => $p_created,
))) {
// echo "Successful";
} // if ($pre->execute(array(
} catch (PDOException $ex) {
echo $ex->getMessage();
} // try
这给了我一个语法错误:
SQLSTATE [42000]:语法错误或访问冲突:1064 SQL语法有错误;检查与您的MariaDB服务器版本相对应的手册,以在第17行的'({mypercent
= 10,mybalance
= 10)mypercent
,'附近使用正确的语法
答案 0 :(得分:1)
有几个选项,每个都有优点和缺点
1)如尼克所说,最简单的注释是两个写三个查询。不要这样做-如果您同时有多个呼叫,那么另一个用户可能会尝试在读取和写入之间更新同一记录。
1b)如果您坚持使用此方法,则可以使用事务。 https://dev.mysql.com/doc/refman/8.0/en/commit.html但是,您需要处理交易存在风险,因此此操作有些过分。
2)第二个最简单的方法(也是我要做的一个)是按照问题中的建议进行“ ON DUPLICATE KEY”操作,然后执行第二个操作以“如果为零则删除”。这样,即使两个事件重叠,它们实际上也将阻止彼此删除记录,或同时更新同一条记录。
重要说明1:您需要在user
上使用UNIQUE索引才能正常工作。或删除“ id”作为字段,并使用“ user”作为主键。
重要注2:您缺少的是在SQL中进行数学运算:
$sql = "INSERT INTO `pledge`(`user`, `location`, `category`, `amount`, `p_created`)
VALUES (:user, :location, :category, :amount, :p_created)
ON DUPLICATE KEY UPDATE `amount`=`amount`-VALUES(amount)";
表示插入不存在的金额,否则,进行匹配并更新记录。
然后进行单独的查询
$sql = "DELETE FROM `pledge` WHERE `user`=:user AND `amount`=0";
(不需要“ user = 0”,但是当您为用户建立索引时,就没有关于“ amount”的索引,它将更快。您可以使用$sql = "DELETE FROM
进行清理认捐WHERE
金额=0";)
3)执行此操作的最理想的方法是在数据库内部使用触发器。您可以告诉SQL Server“如果数量为零,则删除”。或将它们全部混合在一个存储过程中,但它们都太过分了。