如何一次轻松地插入或更新或删除记录

时间:2019-05-14 03:44:12

标签: php mysql pdo

我创建了一个表

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,并添加了一个新的主键,其中包含用户,位置,类别列。

为简化我的原始问题,我仅更新了一列,但实际上更新了两列。

有了这些更改,我能够按预期在命令行(工作台)上进行插入/更新: 插入pledgeuserlocationcategorymypercentmybalancep_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,'附近使用正确的语法

1 个答案:

答案 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“如果数量为零,则删除”。或将它们全部混合在一个存储过程中,但它们都太过分了。