使用两个分支

时间:2016-08-17 21:55:24

标签: mysql

这是我第一篇文章的EDITED版本,因为第一篇文章似乎不够清楚。

我希望根据SELECT查询结果插入或更新(如果存在)。这是我的代码以标准方式工作:

$query = "SELECT * FROM table1 WHERE id1 =".$id1." AND id2=".$id2;
$result = mysqli_query($conn, $query);
if (mysqli_num_rows($result) > 0) {
    $query = "UPDATE table1 SET id3=".$id3." WHERE id1 =".$id1." AND id2 = ".$id2." LIMIT 1";
    $result = mysqli_query($conn, $query);
} else {
    $query = "INSERT INTO table1 (id1, id2, id3) VALUES ($id1, $id2, $id3)";
    $result = mysqli_query($conn, $query);
}

id1,id2,id2值可以重复但在一个条件下(id1和id2不能同时重复。

例如:

只能在以下情况下插入新行

如果这个已存在于table1

id0=0 id1=5 id2=10 id3=15

然后下一个将是:

id0=1 id1=6 id2=10 id3=15

id0=1 id1=5 id2=11 id3=15

行会更新

如果这个已存在于table1

id0=0 id1=5 id2=10 id3=15

,下一个是:

id0=1 id1=5 id2=10 id3=20

因为你注意到id1和id2与表中已有的相同,所以id3会更新。

我的 table1看起来像这样

CREATE TABLE table1 (
  `id0` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `id1` int(11) NOT NULL,
  `id2` int(11) NOT NULL,
  `id3` int(11) NOT NULL
) ENGINE=InnoDB;

我的问题是:是否可以使用“在重复密钥更新时插入”或其他任何方式将上述3个查询合并为一个?

2 个答案:

答案 0 :(得分:3)

首先,您需要将密钥id1和id2设置为一个(组合是唯一的

CREATE TABLE table1 (
  `id0` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `id1` int(11) NOT NULL,
  `id2` int(11) NOT NULL,
  `id3` int(11) NOT NULL,
  UNIQUE KEY `KeyName` (`id1`,`id2`) # <------
) ENGINE=InnoDB;

这样,您无法添加包含相同“id1”和“id2”的两行,然后才能使用以下命令。

INSERT INTO table1 (id1, id2, id3) 
            VALUES ($id1, $id2,$id3)
ON DUPLICATE KEY UPDATE id3 = $id3;

<强>更新

当我们在innoDB表上执行此方法时,有一个错误会在AUTO_INCREMENT

中产生间隙

如果我们使用InnoDB

    CREATE TABLE table1 (
      `id0` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
      `id1` int(11) NOT NULL,
      `id2` int(11) NOT NULL,
      `id3` int(11) NOT NULL,
      UNIQUE KEY `KeyName` (`id1`,`id2`) # <------
    ) ENGINE=InnoDB;

    INSERT INTO table1 (id1, id2, id3) 
                VALUES (5, 10,1)
    ON DUPLICATE KEY UPDATE id3 = 1;

    INSERT INTO table1 (id1, id2, id3) 
                VALUES (5, 10,2)
    ON DUPLICATE KEY UPDATE id3 = 2;

    INSERT INTO table1 (id1, id2, id3) 
                VALUES (6, 10,1)
    ON DUPLICATE KEY UPDATE id3 = 1;

得出以下结果:

+-----+-----+-----+-----+
| id0 | id1 | id2 | id3 |
+-----+-----+-----+-----+
| 1   | 5   | 10  | 2   |
+-----+-----+-----+-----+
| 3   | 6   | 10  | 1   |
+-----+-----+-----+-----+

但是如果我们使用Myisam

    CREATE TABLE table2 (
      `id0` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
      `id1` int(11) NOT NULL,
      `id2` int(11) NOT NULL,
      `id3` int(11) NOT NULL,
      UNIQUE KEY `KeyName` (`id1`,`id2`) # <------
    ) ENGINE=Myisam;

    INSERT INTO table2 (id1, id2, id3) 
                VALUES (5, 10,1)
    ON DUPLICATE KEY UPDATE id3 = 1;

    INSERT INTO table2 (id1, id2, id3) 
                VALUES (5, 10,2)
    ON DUPLICATE KEY UPDATE id3 = 2;

    INSERT INTO table2 (id1, id2, id3) 
                VALUES (6, 10,1)
    ON DUPLICATE KEY UPDATE id3 = 1;

得出以下结果:

+-----+-----+-----+-----+
| id0 | id1 | id2 | id3 |
+-----+-----+-----+-----+
| 1   | 5   | 10  | 2   |
+-----+-----+-----+-----+
| 2   | 6   | 10  | 1   |
+-----+-----+-----+-----+

但是这个错误不应该令人讨厌,如果有必要使用InnoDB,这只会对行重新编号,程序应该知道存在间隙,这与删除行的效果相同。

虽然,它可以通过php执行,但只会在服务器上产生更多负载。

答案 1 :(得分:2)

我可以给你3个例子:

1)处理重复键事件:

INSERT INTO table1 (id1, id2, id3) VALUES ('".$id1."', '".$id2."','".$id3."')
  ON DUPLICATE KEY UPDATE id3='".$id3."'";

2) 替换为:

REPLACE INTO table1 (id1, id2, id3) VALUES ('".$id1."', '".$id2."','".$id3."');

3)同时插入忽略更新:

$q = "INSERT IGNORE INTO table1 (id1, id2, id3) VALUES ('".$id1."', '".$id2."','".$id3."');
    UPDATE table1 SET id3 = ".$id3." WHERE id1=".$id1." AND id2 = ".$id2." LIMIT 1;";

P.S。确保您已使用id1和id2

设置了正确的组合索引

如果这些例子都不起作用:

$query = "SELECT 1 FROM table1 WHERE id1 =".(int)$id1." AND id2=".(int)$id2." LIMIT 1"; 
$result = mysqli_query($conn, $query); 

$query = (mysqli_num_rows($result) > 0) ?
    "UPDATE table1 SET id3=".$id3." WHERE id1 =".$id1." AND id2 = ".$id2." LIMIT 1" : 
    "INSERT INTO table1 (id1, id2, id3) VALUES (".(int)$id1.", ".(int)$id2.", ".(int)$id3.")";
mysqli_query($conn, $query);