【问题标题】:Insert Where Not Exists-Without Primary Key在不存在的地方插入 - 没有主键
【发布时间】:2012-01-21 11:00:06
【问题描述】:

我有 3 个表:牙医、组和 groupdentlink。许多牙医通过 groupdentlink 表链接到许多组。

所以我正在尝试进行查询,它将行插入到 groupdentlink 中(将该州的所有牙医与该州的所有组联系起来),但前提是这些行不存在。简而言之,我想添加新行而不覆盖现有行或复制它们。

所以查询的 intent 类似于:

INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id)
VALUES ('$_POST[id]', '$groupid', '$scheduleid')
WHERE NOT EXISTS ('$_POST[id]', '$groupid')

而且我在 groupdentlink 表中没有任何主键。

提前谢谢你!

【问题讨论】:

    标签: mysql primary-key overwrite


    【解决方案1】:

    如果您真的想编写自己的(工作)查询..


    INSERT INTO groupdentlink (
      f_dent_id, f_group_id, f_schedule_id
    ) SELECT 
        '$_POST[id]'  f_dent_id, 
        '$groupid'    f_group_id,
        '$scheduleid' f_schedule_id
    FROM DUAL
    WHERE NOT EXISTS (
      SELECT 1
      FROM `groupdentlink`
      WHERE 
        f_dent_id = '$_POST[id]' AND f_group_id = '$groupid'
      LIMIT 1 -- will stop mysql to stop searching after first match
    )
    

    ...但是 MySQL 可以为您处理所有这些!


    您不需要主键来让 MySQL 为您处理这个问题,您应该在两列的组合集上添加一个 UNIQUE 键约束。

    查询以将唯一键 dent_group_uniq_key 添加到 groupdentlink

    ALTER TABLE groupdentlink ADD UNIQUE KEY `dent_group_uniq_key` (
      f_dent_id, f_group_id
    );
    

    然后在您的查询中使用INSERT IGNORE

    INSERT IGNORE INTO groupdentlink (
      f_dent_id, f_group_id, f_schedule_id
    ) VALUES (
      '$_POST[id]', '$groupid', '$scheduleid'
    )
    

    INSERT IGNORE 将尝试向您的表中插入一行,如果由于键约束而失败,它将表现得像什么都没发生一样。

    【讨论】:

    • 好的,但如果由于其他原因失败,例如违反外键约束,您不会收到错误消息。
    • @greyfairer 如果插入因重复键而失败,它只会“忽略”,外键约束仍然适用。
    • 非常感谢。我正在使用第二种方法:组合列中的唯一键,因为它对我来说似乎更简单。
    • 子查询中不需要LIMIT 1,在EXISTS子句中找到单行后MySQL会自动停止
    【解决方案2】:
    INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id)
    SELECT '$_POST[id]', '$groupid', '$scheduleid' FROM dual
    WHERE NOT EXISTS (
      select * from groupdentlink 
      where f_dent_id='$_POST[id]'
      and f_group_id='$groupid'
    )
    

    我认为您可以在组合 (f_dent_id, f_group_id) 上创建一个复合主键以确保。

    【讨论】:

    • 作为提示,在您的exists 语句中使用1 而不是*,这样您就不会试图拉回内存中的大列集。稍微加快查询速度(查询越大,影响越大,具体取决于引擎)。
    • @Eric,事实并非如此。请参阅Docs:传统上,EXISTS 子查询以 SELECT * 开头,但它可以以 SELECT 5 或 SELECT column1 或任何内容开头。 MySQL 会忽略此类子查询中的 SELECT 列表,因此没有区别。
    • 啊,MySQL 不这样做——旧版本的 SQL Server 曾经(不知道他们是否仍然这样做),这就是我完成所有工作的地方。我用它作为最佳实践。
    • 找不到任何错误的括号、逗号、引号。有任何想法吗?您发布的代码看起来不错? mysql服务器版本为5.1.60。
    【解决方案3】:

    你几乎成功了!您可以使用 select 语句来提供 insert 语句。只需这样做:

    INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id)
    SELECT '$_POST[id]', '$groupid', '$scheduleid'
    WHERE 
        NOT EXISTS (
        select 
            1 
        from 
            groupdentlink 
        where 
            f_dent_id = $_POST[id] 
            and f_group_id = '$groupid'
        )
    

    【讨论】:

    • 嗯。这是我的查询:“INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id) SELECT '$_POST[id]', '$rowv[id]', '$row[f_sched_id]' WHERE NOT EXISTS (SELECT 1 FROM groupdentlink WHERE f_dent_id = '$_POST[id]' AND f_group_id = '$groupid'" ...我收到语法错误
    • 你需要exists子句的右括号。
    • 您遇到的语法错误是什么,还是不具体?
    • 嗯...你能做not exists子句中的select语句吗?
    • 这是我的完整查询:“INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id) VALUES ('$_POST[memberid]', '$rowv[id]', '$rowv[f_sched_id]') WHERE NOT EXISTS (select * FROM groupdentlink where f_dent_id = '$_POST[memberid]' and f_group_id = '$rowv[id]')"
    【解决方案4】:
    INSERT INTO groupdentlink (f_dent_id, f_group_id, f_schedule_id)
    VALUES ('$_POST[id]', '$groupid', '$scheduleid')
    WHERE NOT EXISTS (
      select * from groupdentlink 
      where f_dent_id='$_POST[id]'
      and f_group_id='$groupid'
    )
    

    而且我认为您可以在组合 (f_dent_id, f_group_id) 上创建复合主键。

    【讨论】:

      猜你喜欢
      • 2019-01-24
      • 1970-01-01
      • 2010-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-11
      • 2021-09-16
      • 2016-03-24
      相关资源
      最近更新 更多