【问题标题】:SQL conditional row insertSQL条件行插入
【发布时间】:2010-05-17 21:26:08
【问题描述】:

如果满足条件,是否可以插入新行?

例如,我有一张没有主键也没有唯一性的表

    +----------+--------+
    | image_id | tag_id |
    +----------+--------+
    |    39    |    8   |
    |    8     |    39  |
    |    5     |    11  |
    +----------+--------+

如果 image_id 和 tag_id 的组合不存在,我想插入一行 例如;

INSERT ..... WHERE image_id!=39 AND tag_id!=8

【问题讨论】:

  • 有什么理由不在两列(组合)上放置唯一约束,执行插入并检查由于违反约束而导致的失败?
  • 不,完全没有理由。两列上的唯一约束完美地工作。感谢您的刷新,简单的解决方案。有时我们会忽略一些事情,让事情变得比实际情况更复杂。
  • 如果尝试添加重复行很常见,我不知道约束是否是最好的做法。

标签: sql mysql syntax


【解决方案1】:

认为您是说:您需要避免此表中出现重复行。

有很多方法可以处理这个问题。最简单的一种:

INSERT INTO theTable (image_id, tag_id) VALUES (39, 8)
WHERE NOT EXISTS 
    (SELECT * FROM theTable 
    WHERE image_id = 39 AND tag_id = 8)

正如@Henrik Opel 指出的那样,您可以在组合列上使用检查约束,但是您必须在其他地方有一个 try/catch 块,这会增加不相关的复杂性。

编辑以解释该评论...

我假设这是一个映射电影和标签之间多对多关系的表。我知道您可能正在使用 php,但我希望下面的 C# 伪代码足够清晰。

如果我有一个Movie 类,添加标签最自然的方法是AddTag() 方法:

class Movie 
{
    public void AddTag(string tagname)
    {
        Tag mytag = new Tag(tagname); // creates new tag if needed

        JoinMovieToTag(this.id, mytag.id);
    }

    private void JoinMovieToTag(movie_id, tag_id)
    {
        /* database code to insert record into MovieTags goes here */

        /* db connection happens here */
        SqlCommand sqlCmd = new SqlCommand("INSERT INTO theTable... /* etc */");

        /* if you have a check constraint on Movie/Tag, this will 
           throw an exception if the row already exists */
        cmd.ExecuteNonQuery(); 
    }
}

在此过程的早期没有实用的方法来检查重复项,因为其他用户可能随时标记电影,所以没有办法解决这个问题。

注意:如果尝试插入重复记录意味着存在错误,则引发错误是合适的,但如果不是,您不希望错误处理程序具有额外的复杂性。

【讨论】:

  • 我目前正在测试@Henrik Opel 解决方案并且工作正常,但是“必须在其他地方有一个 try/catch 块”到底是什么意思?
  • 当我使用 WHERE NOT EXISTS 语句运行这样的条件查询时,mysql 给了我一个语法错误。
【解决方案2】:

尝试使用数据库触发器作为一种有效的方法,根据对表的更新将行添加到不同的表。

【讨论】:

    【解决方案3】:

    我假设你的意思是如果它不包含这些值,你想插入一行。

    我面前没有 MySQL,但一般 SQL 这应该可以工作:

    INSERT INTO a_table (image_id, tag_id) SELECT ? image_id, ? tag_id WHERE  image_id!=39 AND tag_id!=8
    

    如果您的意思是仅在根本不存在这样的行时才插入该行,那么您可以这样做:

    INSERT INTO a_table (image_id, tag_id) SELECT ? image_id, ? tag_id WHERE not exists (SELECT 1 from a_table WHERE image_id!=39 AND tag_id!=8)
    

    【讨论】:

      【解决方案4】:

      如果您将 InnoDB 与事务一起使用,那么您可以简单地先查询数据,然后在您的代码中执行插入,如果现在已经找到具有这些值的行。或者,在两列上添加一个唯一的约束,然后尝试插入。 If 将失败,如果它已经存在,你可以忽略它。 (这比我的第一种方法更不受欢迎。)

      【讨论】:

        【解决方案5】:

        感谢Henrik Opel,因为他发现了包括我在内的我们都忽略了的东西,即对两列的简单唯一约束。最终是最好的解决方案。

        【讨论】:

          【解决方案6】:
          To avoid duplicate row insertion use the below mentioned query:
          
          INSERT INTO `tableName` ( `image_id`, `tag_id`)
          SELECT `image_id`, `tag_id` FROM `tableName`
          WHERE NOT EXISTS (SELECT 1
              FROM `tableName`
              WHERE `image_id` = '39'
              AND `tag_id` = '8'
              );
          

          【讨论】:

          • 为避免重复插入行,请使用主键和外键和/或 UNIQUE 约束。
          猜你喜欢
          • 2013-05-14
          • 1970-01-01
          • 2017-01-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多