Как легко вставить или обновить или удалить запись сразу - PullRequest
0 голосов
/ 14 мая 2019

Я создал таблицу

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-коде.Поскольку это существует, может быть также возможность удалить вместо обновления, если сумма равна нулю.

Обновление:

Спасибо Робби за ваши подсказки.Почему-то я все еще допускаю ошибки.Я пробовал много способов, но ...

Сначала мне пришлось поменять стол.Я удалил идентификатор первичного ключа и добавил новый первичный ключ, содержащий столбцы user, location, category.

Чтобы упростить исходный вопрос, я обновил только один столбец, но на самом деле это два столбца.

С этими изменениями я смог вставить / обновить, как я планировал, в командной строке (Workbench): INSERT INTO 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, на предмет правильного синтаксиса для использования рядом с '(mypercent = 10, mybalance = 10) mypercent,' в строке 17

1 Ответ

1 голос
/ 14 мая 2019

Есть несколько вариантов, каждый с плюсом и минусом

1) Самый простой, как сказал Ник, это комментарии - два - три запроса.Не делайте этого - если у вас есть несколько вызовов одновременно, тогда другой пользователь может попытаться обновить одну и ту же запись между чтением и записью.

1b) Если вы настаивали на таком подходе, вы могли бы использовать транзакции.https://dev.mysql.com/doc/refman/8.0/en/commit.html Однако с транзакциями, которые вам нужно обработать, есть риски, и это немного излишне для этой операции.

2) Второй простейший (и я бы это сделал) - это сделать «ON DUPLICATE KEY», как вы предлагаете в вопросе, а затем вторую операцию «удалить, если ноль».Таким образом, даже если два события перекрываются, они фактически будут препятствовать друг другу в удалении записи, или оба обновят одну и ту же запись.

Критическое примечание 1: вам необходим индекс UNIQUE для user, чтобы это работало,Или удалите «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» не требуется, но, поскольку у вас есть пользовательский индекс, у вас нет индекса по «количеству», этоЭто будет быстрее. Вы можете просто очистить с помощью $sql = "DELETE FROM pledge WHERE сумма =0";)

3) Самый причудливый способ сделать это - использовать триггер внутри базы данных.Вы можете сообщить SQL-серверу, что «если сумма равна нулю, то удалить».Или смешайте все это в хранимой процедуре, но оба они тоже излишни.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...