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

时间:2014-07-14 15:07:02

标签: c# mysql sql variables

我有以下两个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

我希望能够在'questions'表格中插入新行,在'answers'表格中插入多行。

'answers'表中的新行应该与'questions'行中新生成的'question_id'值具有相同的'question_id'。此外,'questions'表中的'correct_answer_id'字段应该等于'answers'表中插入的第一行的'answer_id'。

除了以下步骤之外,还有更有效的方法吗?:

  • 插入值(module_id,author_id,approved,question) 的提问'
  • 在'questions'中获取最后'question_id'
  • 在'answers'中插入值(question_id,answer)
  • 在'questions'中更新值(correct_answer_id)

代码:

    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'

2 个答案:

答案 0 :(得分:1)

可以进行一些简化。首先,你需要将所有命令都包含在一个事务中,因为这是经典的情况,其中插入的记录是严格的关系,并且有一些部分完成的记录是没有意义的。

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

现在,您可以更改插入问题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());

    ..

 }

注意在MySqlCommand构造函数中如何传递对当前事务的引用。这对于打开事务的连接是必需的。

第二部分事情有点复杂。添加第二个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());
    }
    ....
}

现在您可以运行使用lastAnswerID

更新问题的最后一个命令

(最后一点,我认为字段question_id和answer_id是数字类型,而不是varchar,这要求这些字段的参数是Int32而不是varchar)

答案 1 :(得分:0)

是的,您概述的方法效率最高。您需要检索分配给每行INSERTED的AUTO_INCREMENT列的值。但要小心你如何检索这个值。

  • 在&#39;问题&#39;中插入一行表
  • 检索分配给AUTO_INCREMENT列的last_insert_id值
  • 将行插入&#39;答案&#39;表,使用检索到的值&#39; question_id&#39;柱
  • 在插入&#34后立即检索last_insert_id值;正确答案&#34;行
  • 更新&#39;问题&#39;设置&#39; correct_answer_id&#39;柱

MySQL提供LAST_INSERT_ID()功能。这是在成功执行INSERT语句之后,MySQL提供的用于检索分配给AUTO_INCREMENT列的值的机制。 (使用单例插入,它非常简单;只需在插入后立即调用。)

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

许多客户端库提供了内置函数来执行此操作,因此不必准备和执行单独的SELECT语句。 (例如,使用PHP,PDO提供lastInsertId,mysqli提供$insertid。可能是MySQL的C#连接器具有类似的功能。)