【问题标题】:If not exist insert into table mysql problem如果不存在插入表mysql问题
【发布时间】:2011-08-12 11:08:24
【问题描述】:

我正在尝试插入到我的表中,但前提是该信息不存在。

这行得通:

$sql = //"if not exists (select `id` from friends where `id` = :id) " . //ERROR!
"insert into `friends` (`id`, `fb_id`, `name`, `id2`, `fb_id2`, `name2`) " .
"values (:id, :fb_id, :name, :id2, :fb_id2, :name2)";
try 
{
  $stmt = $this->db->prepare($sql); 
  if (!$stmt)
  {
    $errorcode = (string)
    $stmt->errorCode(); 
    trigger_error("mysql errorcode : " . $errorcode, E_USER_ERROR);
    $data = array( "note" => "mysql error code: " . $errorcode );

    return json_encode( $data );    
  } 
  $stmt->bindParam(':id', $id, PDO::PARAM_INT);
  $stmt->bindParam(':fb_id', $fb_id, PDO::PARAM_INT);
  $stmt->bindParam(':name', $name, PDO::PARAM_STR);
  $stmt->bindParam(':id2', $id2, PDO::PARAM_INT); 
  $stmt->bindParam(':fb_id2', $fb_id2, PDO::PARAM_INT); 
  $stmt->bindParam(':name2', $name2, PDO::PARAM_STR); 
  $result = $stmt->execute();
  $stmt->closeCursor(); 
}       
catch (Exception $e)
{
  die ($e->getMessage() ); 
}

我尝试了第一行中提到的if not exists ( select id ... 等,但没有奏效。它返回错误代码00000(string) $stmt->errorCode();,我用谷歌搜索它的意思是:to many mysql connections,这不是问题,因为其他查询工作正常。

不存在的表如何插入,如何获取mysql错误信息?

【问题讨论】:

    标签: mysql sql database


    【解决方案1】:

    我以前从未见过你的语法,在插入子句之前放置了一个存在子句,但以下应该可以工作。

    INSERT INTO `friends`
    SELECT :id, :fp_id, :name, :id2, :fb_id2, :name2
    FROM `friends`
    WHERE NOT EXISTS ( select `id` from friends where `id` = :id )
    LIMIT 1;
    

    刚刚意识到您的朋友表中至少需要一条记录才能完成。

    【讨论】:

    • 补充答案:如果您执行插入...选择。 MySQL 将插入 select 返回的所有行。如果选择没有找到任何东西,则不会插入该位置。
    • 我不是专家,但这看起来很迂回。就是觉得好笑。没有更清洁的方法吗?
    • @PMV,不错的代码,但是这会插入一个“随机”行,您不想在 select 中添加 order by 子句以确保您可以控制插入哪一行?
    • @Johan - 您的欺骗密钥解决方案是正确的,但我认为这不会随机插入任何内容,因为它选择的是常量值。
    • @PMV 你是正确的假设 id 是唯一或主键字段,我们不确定。
    【解决方案2】:
    insert IGNORE into `friends` (`id`, `fb_id`, `name`, `id2`, `fb_id2`, `name2`)
    values (:id, :fb_id, :name, :id2, :fb_id2, :name2)
    

    或者你想防止重复的ID,你可以添加一个触发器

    DELIMITER $$
    
    CREATE TRIGGER bi_friends_each BEFORE INSERT ON friends FOR EACH ROW
    BEGIN
      DECLARE TestId integer;
    
      SELECT id INTO TestId FROM friends WHERE id = new.id LIMIT 1;
      IF (id IS NOT NULL) THEN BEGIN
        /*force an error to prevent insert*/
        SELECT * FROM force_an_error_table_unwilling_to_insert_dup_key;
      END; END IF;
    END $$
    
    DELIMITER ;
    

    请注意,如果 idUNIQUEPRIMARY KEY 字段,则插入重复键将产生错误并回滚任何待处理事务
    如果您使用的是非事务性引擎,MySQL 将在错误点停止插入行,只留下插入的部分行。

    关于为什么要进行IGNORE 测试,您的问题含糊不清。因此,我将回顾一下选项和含义:

    1. 如果你想让一个事务失败,将id设置为主键并照常插入,由此产生的冲突会产生错误并回滚事务。
    2. 如果您只想插入内容而不用担心重复 id 的设置字段是 AUTOINCREMENT 并将 id 的值替换为 null。 INSERT INTO table (id, fb_id,name,id,fb_id2,name2) VALUES (null,:fb_id,:name,:id2,:fb_id2,:name2)
    3. 如果您只希望一次插入不成功,请执行上述INSERT IGNORE ...
    4. 如果您没有交易(MyISAM 等),您可能必须先进行测试SELECT,并且只有在测试显示保存后才能继续进行INSERT a bunch of values

    【讨论】:

    • @ganjan,请阅读更新后的答案。无论如何,将一个名为“id”的字段而不是作为主键是个坏主意!
    【解决方案3】:

    您可以使用INSERT IGNORE 假设您在 id 上有一个唯一索引。有关利弊的讨论,请参阅此帖子:"INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"

    【讨论】:

    • 我用的是insert ignore,没用。可能是因为 id 不像你说的那样是唯一的
    • 是的,id 必须是唯一的。我建议添加该索引,只要它对将使用此表的所有应用程序都有意义。
    【解决方案4】:

    即使您的表中没有任何行,此解决方案也有效。

    INSERT INTO t (
        x,
        y,
        z) (
            SELECT
                '00000',
                '11111',
                '22222'
            FROM
                DUAL
            WHERE
                NOT EXISTS (
                    SELECT
                        1
                    FROM
                        t
                    WHERE
                            c = '00000'
                        AND x = '11111'
                        AND y = '22222'
                )
            LIMIT 1
        );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 2011-08-27
      • 2012-06-09
      • 2012-05-21
      相关资源
      最近更新 更多