MySQL插入记录在PDO中尚未存在的位置

时间:2014-01-03 03:25:13

标签: php mysql sql pdo

我使用PDO(PHP数据对象)进行PHP的数据库交互。这个问题涉及三个数据库表:两个只是带主键的标准表,另一个是描述其他两个表之间关系的表。因此它没有主键,但有2个外键列(table_1_id和table_2_id)。两者都不是唯一的,因为其他两个表中的记录之间存在多对多的关系。

要确定是否应该添加关系,我只需要在关系表中没有与table_1_id和table_2_id匹配的行时插入记录。

理想情况下,我的插页看起来像这样:

INSERT INTO table_3 (table_1_id, table_2_id) VALUES (:id1, :id2)
WHERE NOT EXISTS (
    SELECT 1 FROM table_3 WHERE table_1_id = :id1 AND table_2_id = :id2
)

但是,我知道这不是有效的SQL。 我已经环顾四周,无法确定最佳方法。

感谢您的帮助

4 个答案:

答案 0 :(得分:0)

尝试添加组合主键

ALTER TABLE table_3 ADD PRIMARY KEY(`table_1_id`,`table_2_id`);

答案 1 :(得分:0)

你所谈论的关系被称为“多对多”。

MySql允许您指定多个列作为唯一索引,即列组合唯一索引。

<强> Please see this question in SO that has detailed information about the subject

这可以防止您创建重复的角色,这是您想要完成的。

对于PHP代码,PDO在sql语句失败时抛出错误,因此可以使用try / catch

答案 2 :(得分:0)

首先,您最好在(table_1_id, table_2_id)中明确定义复合PK table_3

CREATE TABLE table3
(
  table_1_id INT NOT NULL, 
  table_2_id INT NOT NULL,
  PRIMARY KEY (table_1_id, table_2_id),
  FOREIGN KEY table_1_id REFERENCES table_1 (table_1_id),
  FOREIGN KEY table_2_id REFERENCES table_2 (table_2_id)
)

其次然后您可以使用IGNORE子句而不是子查询

INSERT IGNORE INTO table_3 (table_1_id, table_2_id) VALUES (:id1, :id2)

这是 SQLFiddle 演示


如果您出于某种原因想要坚持使用子查询版本,那么您的INSERT语句应该看起来像这样

INSERT IGNORE INTO table_3 (table_1_id, table_2_id) 
SELECT ?, ?
  FROM dual
 WHERE NOT EXISTS
(
  SELECT *
    FROM table_3
   WHERE table_1_id = ?
     AND table_2_id = ?
);

这是 SQLFiddle 演示

答案 3 :(得分:0)

一种选择是在两列的组合上定义唯一约束(或主键)。这是规范模式。但是这不允许多行具有相同的值组合。

因此,假设您确实希望允许“重复”行,但只是这一个INSERT语句您不想插入重复行,那么使用SELECT代替VALUES关键字。基本上,编写一个有条件地返回值的SELECT语句。

这样的事可能适合你:

INSERT INTO table_3 (table_1_id, table_2_id) 
SELECT v.id1, v.id2 
  FROM ( SELECT :id1 AS table_1_id, :id2 AS table_2_id ) v
  LEFT
  JOIN table_3 d
    ON d.table_1_id = v.table_1_id
   AND d.table_2_id = v.table_2_id
 WHERE d.table_1_id IS NULL