4
using (var connection = new SqlConnection(...))
{
    string sql = "SELECT * FROM tableA";
    using (var command = new SqlCommand(sql,connection))
    {
        using (var reader = command.ExecuteReader(...))
        {
            //***************Sample Start
            string sql2 = "INSERT into tableB(column1) VALUES('"+reader["column1"]+"')";
            using (var command2 = new SqlCommand(sql2,connection))
            {
                ...
            } 
            //***************Sample End
        }
    }
}

通过使用上面的代码片段,我相信它是在 C# 中处理 SQL 的最佳实践。现在,在我从 tableA 中检索记录列表之后,对于我想插入到 tableB 中的每一行。

但是,它抛出了一个异常

已经有一个打开的 DataReader 与此命令关联,必须先关闭

我知道这个问题可以通过创建另一种方法并从那里插入到表中来解决,我想知道是否还有其他方法。感谢您的任何意见。

4

3 回答 3

7

您需要为插入使用不同的 sql 连接而不是选择...

...但我们可以做得更好。您可以将其重写为一条 sql 语句,如下所示:

INSERT into tableB(column1)
    SELECT column1 FROM tableA

然后像这样一次运行它:

string sql = "INSERT into tableB(column1, column2) SELECT column1, @othervalue As column2 FROM tableA;";
using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
    command.Paramters.Add("@othervalue", SqlDbType.NVarChar, 50).Value = "something";

    connection.Open();
    command.ExecuteNonQuery();
}

单个 sql 语句通常要快得多,并且您最终也可以使用更少的代码。我知道这可能是您真实查询的简化示例,但我向您保证:您可以将其全部重写为一个语句。

此外,有时您仍希望在插入或更新后进行一些客户端处理或显示新记录。在这种情况下,您仍然只需要向数据库发送一个调用,但在该单个调用中将有两个单独的 sql 语句。最终的代码看起来更像这样:

string sql = "INSERT into tableB(column1, column2) SELECT column1, @othervalue As column2 FROM tableA;"
sql += "SELECT columnn1, @othervalue As column2 FROM tableA;";

using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
    command.Paramters.Add("@othervalue", SqlDbType.NVarChar, 50).Value = "something";

    connection.Open();
    using (var reader = command.ExecuteReader() )
    {
        while (reader.Read() )
        {
           //...
        }
    }
}

而且因为其他人提出了 MARS(多个活动结果集),我要补充一点,虽然这可以工作,但我使用它进行插入/更新时的结果好坏参半。当共享连接的所有内容都只进行读取时,它似乎工作得最好。

于 2013-09-13T02:25:07.370 回答
4

正如评论中提到的,您需要一个单独的数据库连接来进行插入。每个连接一次可以处理一个活动语句,这里有两个 - 一个用于SELECT,一个(一次)用于INSERT.

试试这个:

string srcqry = "SELECT * FROM tableA";
using (SqlConnection srccon = new SqlConnection(ConnectionString))
using (SqlCommand srccmd = new SqlCommand(srcqry, srccon))
{
    srccon.Open();
    using (SqlDataReader src = srccmd.ExecuteReader())
    {
        string insqry = "INSERT INTO tableB(column1) VALUES(@v1)";

        // create new connection and command for insert:
        using (SqlConnection inscon = new SqlConnection(ConnectionString))
        using (SqlCommand inscmd = new SqlCommand(insqry, inscon))
        {
            inscmd.Parameters.Add("@v1", System.Data.SqlDbType.NVarChar, 80);
            inscon.Open();

            while (src.Read())
            {
                inscmd.Parameters["@v1"].Value = src["column1"];
                inscmd.ExecuteNonQuery();
            }
        }
    }
}

使用参数解决了 SQL 注入漏洞。您应该始终这样做,而不是从原始用户输入或从数据库中提取的数据构建查询字符串,或者......好吧,总是。如果您愿意,请编写一些帮助方法以使其更容易,只要确保您这样做即可。

于 2013-09-13T02:51:36.363 回答
1

除了一个不好的例子,为什么不把查询简化为

插入 TableB (column1) 从 TableA 中选择 column1

于 2013-09-13T02:24:42.777 回答