简体   繁体   English

两个带有链接字段的插入查询

[英]Two insert queries with linked fields

I have the following two MySQL tables: 我有以下两个MySQL表:

questions:
question_id (PK, AI), module_id (FK), author_id (FK), approved, question, correct_answer_id (FK)

answers:
answer_id (PK, AI), question_id (FK), answer

I want to be able to insert a new row in the 'questions' table and multiple rows in the 'answers' tables. 我希望能够在“问题”表中插入新行,并在“答案”表中插入多行。

The new rows in the 'answers' table should have the same 'question_id' as the newly generated 'question_id' value in the 'questions' row. “答案”表中的新行应与“问题”行中新生成的“ question_id”值具有相同的“ question_id”。 Also, the 'correct_answer_id' field in the 'questions' table should equal the 'answer_id' of the first row inserted in the 'answers' table. 同样,“问题”表中的“ correct_answer_id”字段应等于插入“答案”表中第一行的“ answer_id”。

Is there a more efficiently way to do this than the following steps?: 是否有比以下步骤更有效的方法?

  • insert values (module_id, author_id, approved, question) in 'questions' 在“问题”中插入值(module_id,author_id,已批准,问题)
  • get last 'question_id' in 'questions' 获取“ questions”中的最后一个“ question_id”
  • insert values (question_id, answer) in 'answers' 在“答案”中插入值(question_id,答案)
  • update value (correct_answer_id) in 'questions' 更新“问题”中的值(correct_answer_id)

code: 码:

    string connStr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
    MySqlConnection conn = new MySqlConnection(connStr);

    string queryUpdateQuestions = "INSERT INTO questions (module_id, author_id, approved, question) VALUES (@module_id, @author_id, @approved, @question)";
    MySqlCommand cmdUpdateQuestions = new MySqlCommand(queryUpdateQuestions, conn);
    cmdUpdateQuestions.Parameters.Add("@module_id", MySqlDbType.VarChar);
    cmdUpdateQuestions.Parameters["@module_id"].Value = ddlModules.SelectedValue.ToString();
    cmdUpdateQuestions.Parameters.Add("@author_id", MySqlDbType.VarChar);
    cmdUpdateQuestions.Parameters["@author_id"].Value = Session["UserID"].ToString();
    cmdUpdateQuestions.Parameters.Add("@approved", MySqlDbType.VarChar);
    cmdUpdateQuestions.Parameters["@approved"].Value = 'N';
    cmdUpdateQuestions.Parameters.Add("@question", MySqlDbType.VarChar);
    cmdUpdateQuestions.Parameters["@question"].Value = txtQuestion.Text;

    try
    {
        conn.Open();
        cmdUpdateQuestions.ExecuteNonQuery();
    }
    catch
    {
        lblError.Text="Unable to add question.";
    }
    finally
    {
        conn.Close();
    }

    //????? = get last question_id in 'questions'

    int a = Convert.ToInt32(ddlNoOfAnswers.SelectedValue.ToString());

    for (int b=1; b <= a; b++)
    {
        string queryUpdateAnswers = "INSERT INTO answers (question_id, answer) VALUES (@question_id, @answer)";
        MySqlCommand cmdUpdateAnswers = new MySqlCommand(queryUpdateAnswers, conn);
        cmdUpdateAnswers.Parameters.Add("@answer", MySqlDbType.VarChar);
        cmdUpdateAnswers.Parameters["@answer"].Value = ((TextBox)this.FindControl("txtAnswer" + b)).Text;
        cmdUpdateAnswers.Parameters.Add("@question_id", MySqlDbType.VarChar);
        cmdUpdateAnswers.Parameters["@question_id"].Value = ?????;

        try
        {
            conn.Open();
            cmdUpdateAnswers.ExecuteNonQuery();
        }
        catch
        {
            lblError.Text="Unable to add answer.";
        }
        finally
        {
            conn.Close();
        }
    }

    //update 'correct_answer_id' in 'questions'

Some simplification is possible. 可以进行一些简化。 First of all you need to enclose all of your commands inside a transaction because this is the classical case where the records inserted are in strictly relationships and it doesn't make sense to have some partially completed set of records. 首先,您需要将所有命令包含在事务中,因为这是经典情况,其中插入的记录具有严格的关系,并且没有部分完成的记录集是没有意义的。

using(MySqlConnection conn = new MySqlConnection(connStr))
{
    conn.Open();
    using(MySqlTransaction tr = conn.BeginTransaction())
    {
        ...
        // MySqlCommand code  goes here
        ...
        tr.Commit();
   }
}

Now, you could change your insert question sql to add a second statement that returns the last id inserted 现在,您可以更改插入问题sql以添加第二条语句,该语句返回最后插入的id

 string queryUpdateQuestions = @"INSERT INTO questions (.....);
                                 SELECT LAST_INSERT_ID()";

 using(MySqlCommand cmdUpdateQuestions = new MySqlCommand(queryUpdateQuestions, conn, tr))
 {
    // build the parameters for the question record
    ......

    // Instead of ExecuteNonQuery, run ExecuteScalar to get back the result of the last SELECT
    int lastQuestionID = Convert.ToInt32(cmdUpdateQuestions.ExecuteScalar());

    ..

 }

Notice how, at the MySqlCommand constructor, is passed the reference to the current transaction. 请注意,如何在MySqlCommand构造函数中将引用传递给当前事务。 This is required to work with an connection that has a transaction opened. 这对于与已打开事务的连接一起使用是必需的。

Things are a bit more complex for the second part. 对于第二部分,事情要复杂一些。 The same trick to add a second sql statement could be applied also to the loop that insert the answers, but you need to loop backward if the first question is the correct one 添加第二条sql语句的相同技巧也可以应用于插入答案的循环,但是如果第一个问题正确,则需要向后循环

string queryUpdateAnswers = @"INSERT INTO answers (question_id, answer) 
                             VALUES (@question_id, @answer);
                             SELECT LAST_INSERT_ID()";

using(MySqlCommand cmdUpdateAnswers = new MySqlCommand(queryUpdateAnswers, conn, tr))
{
    // next move the loop inside the using and prepare the parameter before looping to  
    // to avoid unnecessary rebuild of the parameters and the command
    cmdUpdateAnswers.Parameters.Add("@answer", MySqlDbType.VarChar);
    cmdUpdateAnswers.Parameters.Add("@question_id", MySqlDbType.Int32);

    int lastAnswerID = 0;  
    // Loop backward so the last answer inserted is the 'correct' one and we could get its ID
    for (int b=a; b >= 1; b--)
    {
         cmdUpdateAnswers.Parameters["@answer"].Value = ((TextBox)this.FindControl("txtAnswer" + b)).Text;
         cmdUpdateAnswers.Parameters["@question_id"].Value = lastQuestionID;
         lastAnswerID = Convert.ToInt32(cmdUpdateAnswers.ExecuteScalar());
    }
    ....
}

Now you could run the last command that update the question with the lastAnswerID 现在,您可以运行最后一个命令,使用lastAnswerID更新问题

(A last note, I suppose that the fields question_id and answer_id are of type numeric, not varchar, this requires that the parameters for these fields will be an Int32 not a varchar) (最后一点,我假设字段question_id和answer_id是数字类型,而不是varchar类型,这要求这些字段的参数将是Int32而不是varchar)

Yes, the approach you outline is the most efficient. 是的,您概述的方法是最有效的。 You will need to retrieve the value assigned to the AUTO_INCREMENT column of each row INSERTED. 您将需要检索分配给每行“插入”的AUTO_INCREMENT列的值。 But be careful how you retrieve that value. 但是请注意如何获取该值。

  • insert a row into 'questions' table 在“问题”表中插入一行
  • retrieve last_insert_id value assigned to AUTO_INCREMENT column 检索分配给AUTO_INCREMENT列的last_insert_id值
  • insert row to 'answers' table, using retrieved value for 'question_id' column 使用“ question_id”列的检索值将行插入“答案”表
  • retrieve last_insert_id value immediately following insert of "correct answer" row 插入“正确答案”行后立即检索last_insert_id值
  • update row in 'questions' to set 'correct_answer_id' column 更新“问题”中的行以设置“ correct_answer_id”列

MySQL provides the LAST_INSERT_ID() function. MySQL提供了LAST_INSERT_ID()函数。 That's the mechanism that MySQL provides to retrieve the value assigned to an AUTO_INCREMENT column, following the successful execution of an INSERT statement. 这是MySQL成功执行INSERT语句后提供的机制,用于检索分配给AUTO_INCREMENT列的值。 (With singleton inserts, it's very straightforward; it just has to be called immediately following the insert.) (对于单例插入,这非常简单;只需在插入之后立即调用它即可。)

Ref: http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id 参考: http : //dev.mysql.com/doc/refman/5.5/zh-CN/information-functions.html#function_last-insert-id

A lot of client libraries provide a builtin function to do this, so it's not necessary to prepare and execute a separate SELECT statement. 许多客户端库都提供了内置函数来执行此操作,因此无需准备和执行单独的SELECT语句。 (For example, with PHP, PDO provides lastInsertId , mysqli provides $insertid . It's likely that the C# connector for MySQL has a similar function.) (例如,对于PHP,PDO提供lastInsertId ,mysqli提供$insertid的C#连接器可能具有类似的功能。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM