【问题标题】:IF NOT EXISTS INSERT INTO ELSE UPDATE SQL如果不存在,则插入 ELSE UPDATE SQL
【发布时间】:2019-06-20 20:03:16
【问题描述】:

我做错了什么?

我正在创建一个以数据库为中心的 Windows 窗体 C# 应用程序。在我的表单应用程序中,我有 4 个文本框,可将其数据插入到一个简单的数据库表中。

如果我在 textBox1(Customer_Name) 中输入内容,然后单击名为“检查并保存”的按钮,我希望该操作检查 Customer_Name 是否存在。

如果不存在,则将数据插入数据库。

如果确实存在,它应该使用输入到 textBox1-4 的信息更新我的数据库

我有这个代码:

private void Button1_Click(object sender, EventArgs e)
{
    con.Open();

    SqlCommand cmd = new SqlCommand("IF NOT EXISTS (SELECT * FROM [Customers] WHERE Customer_Name=@aa BEGIN INSERT INTO [Customers](Customer_Name,Cellphone_Number,Telephone_Number,Alternative_Number) VALUES(@aa,@bb,@cc,@dd) END ELSE BEGIN UPDATE [Customers] SET Customer_Name=@aa, Cellphone_Number=@bb, Telephone_Number=@cc, Alternative_Number=@dd END", con);

    cmd.Parameters.AddWithValue("@aa", textBox1.Text);   
    cmd.Parameters.AddWithValue("@bb", textBox2.Text);  
    cmd.Parameters.AddWithValue("@cc", textBox3.Text);  
    cmd.Parameters.AddWithValue("@dd", textBox4.Text);

    con.Close();
}

点击按钮时没有信息被输入到数据库中,也没有任何信息更新。

【问题讨论】:

  • 您到底在哪里执行该命令?因为您发布的代码没有做任何事情。
  • 我认为您的陈述中也缺少括号。 IF NOT EXISTS (SELECT * FROM [Customers] WHERE Customer_Name=@aa)
  • 您没有执行命令。你必须使用 cmd.ExecuteNonQuery()
  • 另外,对于维护点,考虑使用更具描述性的名称aabbccdd 不是。 textBox1textBox2 也不是...

标签: c# sql-server


【解决方案1】:

我做错了什么?

您没有执行命令。
完全配置命令后,您的代码应该有一个cmd.ExecuteNonQuery();

但是,一旦添加了它,就会从 SQL Server 收到语法错误消息。 这是因为您缺少 Exists 运算符的右括号。

请注意,这远不是您在此代码中做错的唯一事情:

  1. 您将 UI 代码与应用程序代码混合在一起。
  2. 您正在使用全局变量(或至少是一个字段)来保存 SqlConnection 的实例。
  3. 您为参数和 texbox 使用了糟糕的名称。
  4. 您正在使用AddWithValue
  5. 您正在使用的“upsert”模式很麻烦并且可能存在问题。

这里有更好的选择:

第一
你应该阅读n-tier architectural pattern
对于winforms,通常使用MVP实现。
一方面,不要将文本框数据直接发送到您的数据库,而是创建一个 Customr 类来保存数据,并使用它在您的代码中传递客户数据。

第二
最佳做法是在 using 语句中使用局部变量,以确保处理 SqlConnectioninstance 并将底层连接返回到连接池。

第三
想象一下,必须更改看起来像这样的代码中的某些内容与更改看起来像这样的代码中的某些内容:

cmd.Parameters.Add(@"CustomerName", SqlDbType.NVarChar).Value = customerName;

现在您无需阅读 SQL 即可了解该参数的含义 - 花在理解代码上的时间和精力越少越好。

第四
链接中的文章详细解释了为什么会出现问题, 但重点是参数的数据类型必须从用法中推断出来, 这可能会因为错误地推断出数据类型而产生错误——甚至最坏的情况——错误的数据静默地输入到数据库中。

第五
更好的模式是先更新,然后有条件地插入 - 就像在 Aaron Bertrand's answer here 中演示的那样 - 在多用户(或多线程)环境中将整个事物包装在一个事务中。

话虽如此,修改后的代码应该看起来更像这样:

private void AddOrUpdateCustomer(Customer customer)
{
    // Data validity tests omitted for brevity - but you should ensure 
    // customer has all it's properties set correctly.

    // Readable, properly indented code - Isn't that much easier to debug?
    var sql = @"
        SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
        BEGIN TRANSACTION;
        UPDATE [Customers] 
        SET 
        Cellphone_Number = @Cell, 
        Telephone_Number = @Telephone, 
        Alternative_Number = @Alternative
        WHERE Customer_Name = @Name 

        IF @@ROWCOUNT = 0
        BEGIN 

        INSERT INTO [Customers](Customer_Name, Cellphone_Number, Telephone_Number, Alternative_Number) 
        VALUES(@Name, @Cell, @Telephone, @Alternative) 

        END
        COMMIT TRANSACTION;"; 


    // connectionString should be obtained from configuration file
    using(var con = new SqlConnection(connectionString))
    {
        using(var cmd = new SqlCommand(sql, con))
        {
            cmd.Parameters.Add(@"Name", SqlDbType.NVarChar).Value = customer.Name;
            cmd.Parameters.Add(@"Cell", SqlDbType.NVarChar).Value = customer.Cellphone;
            cmd.Parameters.Add(@"Telephone", SqlDbType.NVarChar).Value = customer.Telephone;
            cmd.Parameters.Add(@"Alternative", SqlDbType.NVarChar).Value = customer.AlternativeNumber;

            con.Open();
            cmd.ExecuteNonQuery();
        }
    }
}

【讨论】:

  • 虽然对于架构相关的建议,我建议 codereview.stackexchange.com 您的第五点非常好。请注意 OP 更新是错误的,请检查我的答案中的编辑,因为您的答案会更新整个表格。
  • @bradbury9 不错。我没有注意到这一点。谢谢!
  • 我没有注意到,直到我收到编辑建议 ;-)
  • 关于“应从配置文件中获取connectionString”我会进行DI,因此如有必要可以进行集成测试,但也许添加DI对答案来说太过分了,用shot弹枪杀死文件。
  • 是的,我认为配置文件就足够了——而且,即使您使用的是 DI,最好从配置文件中读取 connectionString(然后注入 dal 类) .
【解决方案2】:

我检查了你的代码有几个问题。

private void button1_Click(object sender, EventArgs e)
        {
            SqlConnection con = new SqlConnection("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            con.Open();

            SqlCommand cmd = new SqlCommand("IF NOT EXISTS (SELECT * FROM [Customers] WHERE Customer_Name=@aa BEGIN INSERT INTO [Customers](Customer_Name,Cellphone_Number,Telephone_Number,Alternative_Number) VALUES(@aa,@bb,@cc,@dd) END ELSE BEGIN UPDATE [Customers] SET Customer_Name=@aa, Cellphone_Number=@bb, Telephone_Number=@cc, Alternative_Number=@dd END", con);

            cmd.Parameters.AddWithValue("@aa", textBox1.Text);
            cmd.Parameters.AddWithValue("@bb", textBox2.Text);
            cmd.Parameters.AddWithValue("@cc", textBox3.Text);
            cmd.Parameters.AddWithValue("@dd", textBox4.Text);

            cmd.ExecuteNonQuery();

            con.Close();
        }

更新语句中缺少括号和条件。我已经修复了查询。您可以再试一次并检查 SQL 连接字符串。

IF NOT EXISTS (SELECT * FROM [Customers] WHERE Customer_Name=@aa) BEGIN INSERT INTO [Customers](Customer_Name,Cellphone_Number,Telephone_Number,Alternative_Number) VALUES(@aa,@bb,@cc,@dd) END ELSE BEGIN UPDATE [Customers] SET Customer_Name=@aa, Cellphone_Number=@bb, Telephone_Number=@cc, Alternative_Number=@dd WHERE Customer_Name=@aa END

插入数据

更新数据

【讨论】:

    【解决方案3】:

    我没有检查 SQL 语句。

    但是添加后可以查看代码吗,因为不执行命令数据库是看不到变化的。

    cmd.ExecuteNonQuery();
    

    之前

     con.Close();
    

    【讨论】:

    • 这是最大的问题,但不是唯一的问题,问题有不同的问题,这个答案只解决其中一个问题
    猜你喜欢
    • 2018-09-17
    • 1970-01-01
    • 2021-02-19
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多