【问题标题】:INSERT INTO if not exists SQL server如果不存在 SQL 服务器,则插入
【发布时间】:2012-03-27 18:46:11
【问题描述】:

我的数据库结构如下:

用户

userid (Primary Key)
username

groupid (PK)
groupName

用户组

userid (Foreign Key)
groupid (Foreign Key)

用户第一次登录时,我希望将他们的信息添加到用户表中。所以基本上我想要的逻辑如果

if (//users table does not contain username)
{
INSERT INTO users VALUES (username);
}

如何使用 SQL Server/C# 智能地做到这一点?

【问题讨论】:

    标签: c# sql sql-server database-design


    【解决方案1】:

    或者使用新的 MERGE 语法:

    merge into users u
    using ( 
       select 'username' as uname
    ) t on t.uname = u.username
    when not matched then 
      insert (username) values (t.uname);
    

    【讨论】:

    • 很好(尽管在只考虑单个操作时可能没有必要)
    • @Damien_The_Unbeliever - 当你有high concurrency 时值得考虑。可能不是这里的情况,但我 +1。
    • @MikaelEriksson - 你表示它仍然需要serializable 来避免一些问题 - 那么这种方法和其他方法之间是否有一些明显的区别?
    • @Mikael Eriksson:在默认隔离级别,MERGE 不是并发的:另一个连接可以在匹配和合并的插入部分之间插入。 Example code here
    • @MikaelEriksson:可序列化提示和并发不能一起使用,因为可序列化的效果是不并发。毕竟serial是concurrent的反义词。我认为高并发的公认方法是在发生冲突的罕见情况下捕获主键冲突。
    【解决方案2】:

    基本上你可以这样做:

    IF NOT EXISTS (SELECT * FROM USER WHERE username = @username)
        INSERT INTO users (username) VALUES (@username)
    

    但是说真的,您如何知道用户是否是第一次访问您的网站? 当有人在您的网站上注册而不是登录时,您必须在表用户中插入记录。

    【讨论】:

    • @Damien_The_Unbeliever,谢谢!
    • 顺便说一句——到目前为止,你已经赢得了超过 1000 名代表——现在是时候选择一个像样的名字了吗?
    • 我会知道他们是否是第一次登录,因为他们的名字将在数据库中!我的网站上没有注册;我使用来自另一个站点的外部身份验证:)。感谢您的回复!
    • 您是否考虑过为此使用存储过程?
    【解决方案3】:
    IF NOT EXISTS (select * from users where username = 'username')
    BEGIN
        INSERT INTO ...
    END
    

    【讨论】:

      【解决方案4】:

      我会首先在数据库上创建一个存储过程来进行检查并在必要时插入:

      CREATE PROCEDURE AddNewUserProc
      (
      @username       VarChar(50) -- replace with your datatype/size
      )
      
      AS
      
          IF NOT EXISTS (SELECT * FROM users WHERE username = @username)
          BEGIN
              INSERT INTO users
              VALUES (@username)
          END
      

      然后是应用程序上将调用此过程的方法

      public void AddNewUserMethod(string userName)
      {
          SqlConnection connection = new SqlConnection("connection string");
          SqlCommand command = new SqlCommand("AddNewUserProc", connection);
      
          command.CommandType = CommandType.StoredProcedure;
          command.Parameters.Add("username", SqlDbType.VarChar, 50).Value = userName;
      
          try
          {
              connection.Open();
              command.ExecuteNonQuery();
          }
          finally
          {
              if (connection.State == ConnectionState.Open) { connection.Close(); }
          }
      }
      

      注意将此保留为替代/历史,但为了正确起见,正确的方法是使用 Merge 语句,请参阅答案 @987654321 @或结帐 MS doc https://docs.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15

      【讨论】:

        【解决方案5】:

        有一个简单的解决方案!我在这个post找到它!

        INSERT INTO users (Username) 
        SELECT ('username')
        WHERE NOT EXISTS(SELECT * FROM users WHERE Username= 'username')
        

        在我的项目中,我需要使用 2 个值。所以我的代码是:

        INSERT INTO MyTable (ColName1, ColName2) 
        SELECT 'Value1','Value2' 
        WHERE NOT EXISTS
        (SELECT * FROM MyTable WHERE ColName1 = 'Value1' AND ColName2= 'Value2')
        

        希望这会有所帮助!

        【讨论】:

          【解决方案6】:

          下面的代码是一个方法,如果用户已经存在则返回0,并返回刚刚添加的新用户ID

            private int TryToAddUser(string UserName)
                  {
                      int res = 0;
                      try
                      {
                          string sQuery = " IF NOT EXISTS (select * from users where username = @username) \n\r" + 
                          " BEGIN \n\r" + 
                          "     INSERT INTO users values (@username) \n\r" + 
                          " SELECT SCOPE_IDENTITY() \n\r " + 
                          " END \n\r " + 
                          " ELSE SELECT 0";
                          using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand())
                          {
                              cmd.CommandText = sQuery;
                              cmd.Parameters.AddWithValue("@username",UserName);
                              cmd.Connection = new System.Data.SqlClient.SqlConnection("SomeSqlConnString");
                              cmd.Connection.Open();
                              res = (int)cmd.ExecuteScalar();
                              cmd.Connection.Close();
                          }
                      }
                      catch (Exception ex)
                      {
                          MessageBox.Show(ex.Message);
                      }
                      return res;
                  }
          

          【讨论】:

            【解决方案7】:

            @gbn 回答需要 SQL Server 2008 或更高版本。我尝试了一种非合并的方式来做到这一点。也许丑陋,但它有效。

            declare @user varchar(50)
            set @user = 'username'
            insert into users (username) 
            select @user
            where not exists (
             select username 
             from users 
             where username = @user
            );
            

            如果您想测试任何答案,这里是表的 SQL -

            CREATE TABLE [dbo].[users](
                [userid] [int] NULL,
                [username] [varchar](50) NULL
            )
            
            INSERT [dbo].[users] ([userid], [username]) VALUES (1, N'John')
            INSERT [dbo].[users] ([userid], [username]) VALUES (2, N'David')
            INSERT [dbo].[users] ([userid], [username]) VALUES (3, N'Stacy')
            INSERT [dbo].[users] ([userid], [username]) VALUES (4, N'Arnold')
            INSERT [dbo].[users] ([userid], [username]) VALUES (5, N'Karen')
            

            【讨论】:

              【解决方案8】:

              这是一个解决您的问题的(可能过于简单化)示例。请注意,始终最好使用参数来防止注入攻击,尤其是在验证用户时。

              CREATE PROCEDURE AddUser
                @username varchar(20)
              AS
                IF NOT EXISTS(SELECT username FROM users WHERE username=@username)
                  INSERT INTO users(username) VALUES (@username)
              

              【讨论】:

                猜你喜欢
                • 2018-09-17
                • 1970-01-01
                • 2015-07-06
                • 2021-02-19
                • 1970-01-01
                • 1970-01-01
                • 2011-09-01
                • 1970-01-01
                • 2023-03-21
                相关资源
                最近更新 更多