SQL 服务器:使用 select 和其他参数插入

Posted

技术标签:

【中文标题】SQL 服务器:使用 select 和其他参数插入【英文标题】:SQL server: insert into using select and other parameter 【发布时间】:2014-06-11 22:32:03 【问题描述】:

我有 3 个表:projectsma​​nagersproject_manager

经理

manager_id (int, PK) 经理姓名

项目

project_id (int, PK) 项目名称

project_manager

project_id (int, PK) manager_id (int, PK)

假设经理当前已登录(因此我们知道 ma​​nager_id 是什么)并且他想通过在 txtName 文本框中输入名称来创建一个新的 Project并点击“创建”按钮。我试着写:

(1) 将新项目(名称)插入到 projects 表和

中的查询

(2) 将 project_idma​​nager_id 插入 project_manager 表的单个查询

但在第三个查询字符串出现语法错误,这不是一个好方法,因为插入项目表(查询 1)可能会成功,但插入其他表(查询 2)可能会失败,我不太了解“高级”东西”的SQL,肯定需要帮助:

string CS = ConfigurationManager.ConnectionStrings["CTECS"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))

    string q1 = "SELECT COUNT(*) FROM [projects] WHERE project_name = @Name";
    SqlCommand cmd = new SqlCommand(q1, con);
    cmd.Parameters.AddWithValue("@Name", txtName.Text);
    con.Open();
    int i = (int)cmd.ExecuteScalar();
    if (i < 1)
    
        string Command = "INSERT INTO [dbo].[projects] (project_name) VALUES (@Name)";
        cmd = new SqlCommand(Command, con);
        cmd.Parameters.AddWithValue("@Name", txtName.Text);
        cmd.ExecuteNonQuery();

        Command = "INSERT INTO [project_manager] (project_id, manager_id) VALUES (SELECT project_id FROM [projects] WHERE project_name = @Name, @ID)";
        cmd = new SqlCommand(Command, con);
        // Provide the value for the parameter
        cmd.Parameters.AddWithValue("@Name", txtName.Text);
        cmd.Parameters.AddWithValue("@ID", currentUser.userID.ToString());
        cmd.ExecuteNonQuery();
    
    else
    
        Panel1.Visible = true;
        lblMessage.CssClass = "alert alert-error";
        lblMessage.Text = "This project's name has been already used.";
        return;
    

【问题讨论】:

不,这是对的,我的错.. 【参考方案1】:

我觉得第三条sql语句应该是:

INSERT INTO [project_manager] (project_id, manager_id) SELECT project_id, @ID FROM [projects] WHERE project_name = @Name

【讨论】:

如果他有多个同名项目,他最终会在表中插入多条记录。 同意。最好的方法是在插入 [projects] 后使用 SCOPE_IDENTITY() 来获取 project_id(假设 project_id 是一个标识列) @MikeHixson 你能否给出一个完整的答案来解释你的想法,我很难弄清楚? @RonaldinhoState 你的原始帖子在你编辑它之前说:“我试过这个,但在第三个查询字符串出现语法错误”。我的答复是对那个声明。如果你用我的回答中的那个替换你的第三个 sql 语句,它应该会处理你的语法错误。 @MikeHixson 我的意思是您在评论中提到的使用 SCOPE_IDENTITY() 的“更好”想法【参考方案2】:

您是否在单用户模式下使用服务器?我不这么认为。首先,您必须在事务中执行此操作。最好的方法-SP。检查项目是否存在并不能保证插入时它不存在。

CREATE PROC usp_InsertProject(@project_name varchar(255), @manager_id int)
AS
SET NOCOUNT ON
DECLARE @project_id int
BEGIN TRY
  BEGIN TRAN
    INSERT INTO [dbo].[projects] (project_name) VALUES (@project_name)
    SELECT @project_id = SCOPE_IDENTITY()
    INSERT INTO [project_manager] (project_id, manager_id)
                                  VALUES(@project_id, @manager_id)
  COMMIT TRAN
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber
       ,ERROR_MESSAGE() AS ErrorMessage
   ROLLBACK TRAN
END CATCH

GO

然后

string CS = ConfigurationManager.ConnectionStrings["CTECS"].ConnectionString;
using (SqlConnection con = new SqlConnection(CS))

    SqlCommand cmd = new SqlCommand("usp_InsertProject", con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@project_name", txtName.Text); // you must validate text value before passing
    cmd.Parameters.AddWithValue("@manager_id", currentUser.userID);

    con.Open();
    using(SqlDataReader reader = cmd.ExecuteReader())
    
        if(reader.Read())
        
           // the error occured in SP
           // reader[0] is error number
           // record[1] is error message
        
    

【讨论】:

我很难理解这个答案,但我会研究“事务”SQL。 注意,如果你想避免项目名称重复,你必须对projects.project_name有唯一的约束。【参考方案3】:

你的逻辑一开始就不正确

SELECT project_id FROM [projects] WHERE project_name = @Name

可能会返回多个结果。您可能已经进行了检查以确保只有一个项目具有同一个名称,但系统不知道这一点,您最终会在表中插入多条记录

解决方法可以是您将其更改为(只是为了使其工作)

INSERT INTO [project_manager] (project_id, manager_id) SELECT project_id, @ID FROM [projects] WHERE project_name = @Name

但是,不推荐。

您需要保存为项目名称生成的 id 并将它们传递给您的查询。

INSERT INTO [project_manager] (project_id, manager_id) VALUES (@ProjectID, @ID)

【讨论】:

您能解释一下“...但是系统不知道这一点,您最终会在表中插入多条记录”这个术语吗? 假设数据库中有2条项目名称为“Project ABC”的记录。然后您的语句将在 project_manager 表中插入 2 个条目。 不可能发生,因为第一个查询“SELECT COUNT(*) FROM [projects] WHERE project_name = @Name”将检查名称是否令人兴奋,对吗? 您可以放置​​多个检查以避免这种情况。但是,您需要以正确的方式进行操作。【参考方案4】:

首先,您将整个逻辑转移到安全且易于维护的存储过程中。此外,在您的情况下,sqlserver 只有一次命中,而不是 3 次。

也可以使用 @@identity 或 SCOPE_IDENTITY() 来获取插入的项目 ID 的 ID。

所以像@Hamlet-Hakobyan 建议的那样制作一个 sp 和代码。试着让世界从复杂变得简单,而不是从简单变得复杂。

你的代码作为基本的东西很好理解,但不是在专业场景中。

【讨论】:

以上是关于SQL 服务器:使用 select 和其他参数插入的主要内容,如果未能解决你的问题,请参考以下文章

Pyodbc 未检测 SQL 语句中的参数标记(即 - 插入表 SELECT ...)到 Hive 表。这个问题有解决方法吗?

mybatis之映射器(select)

基于其他 SELECT 参数的不等式基础 SQL

insert 插入带select查询

关于SQL server 插入数据时语言和特殊字符的处理

Oracle - PL/SQL - 使用 SELECT 作为 VALUES 插入所有