如果不存在则插入——SQL server

14

我有一个以下结构的数据库:

用户

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#智能地实现这个?

8个回答

21

或者使用新的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
1
@Damien_The_Unbeliever - 当你有高并发时,值得考虑(http://dba.stackexchange.com/a/13384/2103)。也许这里不是这种情况,但我还是给你点赞。 - Mikael Eriksson
1
@Mikael Eriksson:在默认隔离级别下,MERGE 不是并发的:另一个连接可以在合并的匹配和插入部分之间插入。示例代码在此处 - Andomar
2
@MikaelEriksson:可序列化提示和并发不相容,因为可序列化的效果是不允许并发。毕竟,“serial”是“concurrent”的反义词。我认为高并发的通用方法是在极少数冲突发生的情况下捕获主键冲突。 - Andomar
如果目标表有大约1000-1500万行并且用户名列已经建立索引,那么这种方法是否可行?如果我们有多个要检查的列,并且它们也都建立了索引,那该怎么办? - Steam
显示剩余4条评论

12

基本上你可以像这样做:

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

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


4
完全是旁注,你迄今已经赚得超过1K声望了 - 是不是该选一个像样的名字了? - Damien_The_Unbeliever
我会知道他们是否是第一次登录,因为他们的名字将出现在数据库中!我的网站上没有注册;我使用另一个网站的外部认证:)感谢回复! - Simon Kiely
你考虑过使用存储过程吗? - sam yi

4
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语句,详情请参考答案https://dev59.com/n2kw5IYBdhLWcg3wyNgV#9649040或查看微软文档https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql?view=sql-server-ver15


2
有一个简单的解决方案!我在这篇文章中找到了它:post
INSERT INTO users (Username) 
SELECT ('username')
WHERE NOT EXISTS(SELECT * FROM users WHERE Username= 'username')

在我的项目中,我需要用两个值来完成。所以我的代码是:

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

希望这能帮到你!

1
以下代码是一个方法,如果用户已经存在,则返回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;
        }

1
@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')

0

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接