如何使用 SqlCommand 返回多个结果集?
Posted
技术标签:
【中文标题】如何使用 SqlCommand 返回多个结果集?【英文标题】:How do I return multiple result sets with SqlCommand? 【发布时间】:2012-10-03 19:38:37 【问题描述】:我可以执行多个查询并只执行一次SqlCommand
就返回它们的结果吗?
【问题讨论】:
多个 SELECT 查询?还是插入/更新?如果查询是 SELECT,它们是否返回具有相同布局的数据?拜托,这个问题太模糊了。 多个 SELECT 查询,都具有相同的布局。我不能使用 UNION,因为我有一些 T-SQL 逻辑阻止我这样做。 【参考方案1】:见SqlDataReader.NextResult(调用SqlCommand.ExecuteReader返回一个SqlDataReader):
在读取批处理 Transact-SQL 语句的结果时,将数据读取器推进到下一个结果 [集]。
例子:
string commandText = @"SELECT Id, ContactId
FROM dbo.Subscriptions;
SELECT Id, [Name]
FROM dbo.Contacts;";
List<Subscription> subscriptions = new List<Subscription>();
List<Contact> contacts = new List<Contact>();
using (SqlConnection dbConnection = new SqlConnection(@"Data Source=server;Database=database;Integrated Security=true;"))
dbConnection.Open();
using (SqlCommand dbCommand = dbConnection.CreateCommand())
dbCommand.CommandText = commandText;
using(SqlDataReader reader = dbCommand.ExecuteReader())
while(reader.Read())
subscriptions.Add(new Subscription()
Id = (int)reader["Id"],
ContactId = (int)reader["ContactId"]
);
// this advances to the next resultset
reader.NextResult();
while(reader.Read())
contacts.Add(new Contact()
Id = (int)reader["Id"],
Name = (string)reader["Name"]
);
其他例子:
C# Multiple Result Sets Executing a Query That Returns Multiple Result Sets with SqlDataReader : SqlCommand Select « ADO.Net « C# / CSharp Tutorial【讨论】:
这正是我想要的。谢谢!【参考方案2】:创建一个有多个选择的Stored Procedure
,并填充DataSet
。
using (SqlConnection conn = new SqlConnection(connection))
DataSet dataset = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("MyProcedure", conn);
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.Fill(dataset);
return dataset;
对于存储过程中的每个选择,返回的数据集的 Tables 数组中都会有一个 DataTable
。
【讨论】:
+1 因为这是“更简单的方法”;但是,它不一定是存储过程 - 批处理中的多个语句 应该 可以正常工作 IIRC。 我相信你是对的,我只是不记得了。我知道它适用于存储过程。【参考方案3】:“dapper”之类的工具让这一切变得非常简单,无论您使用的是临时文本查询还是存储过程;例如:
using(var multi = conn.QueryMultiple(sql, args))
var customers = multi.Read<Customer>().AsList(); // first grid
var regionName = multi.ReadFirstOrDefault<string>(); // second grid
var addresses = multi.Read<Address>().AsList(); // third grid
// todo: use those things
也可以通过Read[<T>]
的可选参数读取单个网格而无需缓冲(作为阅读器本身的打开IEnumerable<T>
)。
【讨论】:
【参考方案4】:我调用一个 sproc 并获得多个带有对象的结果集,所以你最终得到一个
List<List<Dictionary<string, object>>>
在 multiResultsSet 中,每个结果集都是那么
List<Dictionary<string, object>>
他们可以是cast to their types 并根据需要转换为模型。
在你设置好所有需要的 sproc 命令后,将它传递给这个:
private static List<List<Dictionary<string, object>>> ProcessReader(SqlCommand command)
var tables = new List<List<Dictionary<string, object>>>();
using (var reader = command.ExecuteReader())
do
var table = new List<Dictionary<string, object>>();
while (reader.Read())
table.Add(Read(reader));
tables.Add(table);
while (reader.NextResult());
return tables;
并且 Read() 相当简单。
private static Dictionary<string, object> Read(IDataRecord reader)
var row = new Dictionary<string, object>();
for (var i = 0; i < reader.FieldCount; i++)
var val = reader[i];
row[reader.GetName(i)] = val == DBNull.Value ? null : val;
return row;
【讨论】:
【参考方案5】:我正在使用字典方法。 您可以使用 Newton Json 将其转换为 json。 这样你就不会被类型和 IDataRecord 所束缚
public List<List<Dictionary<string, object>>> ExecuteSqlReader(string cmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
var sqlCmd = new SqlCommand(cmd);
var allRecord = new List<List<Dictionary<string, object>>>();
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
using (var reader = sqlCmd.ExecuteReader())
if (reader.HasRows)
var result = new List<Dictionary<string, object>>();
while (reader.Read())
result = GetTableRowData(reader);
allRecord.Add(result);
while (reader.NextResult())
if (reader.HasRows)
var result = new List<Dictionary<string, object>>();
while (reader.Read())
result = GetTableRowData(reader);
allRecord.Add(result);
return allRecord;
【讨论】:
【参考方案6】:这是我用来返回多个结果集的方法。
public abstract class BaseRepo
private string _connectionString;
protected BaseRepo(string connectionString)
_connectionString = connectionString;
private SqlConnection GetSqlConnection(int commandTimeout, CommandType commandType, ref SqlCommand sqlCmd)
var connection = new SqlConnection(_connectionString);
connection.Open();
sqlCmd.Connection = connection;
sqlCmd.CommandTimeout = commandTimeout;
sqlCmd.CommandType = commandType;
return connection;
protected int ExecuteSql(SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
return sqlCmd.ExecuteNonQuery();
protected IEnumerable<T> ExecuteSqlReader<T>(Func<IDataRecord, T> CreateObject, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
using (var reader = sqlCmd.ExecuteReader())
return ExecuteReader(CreateObject, reader);
protected Tuple<IEnumerable<T1>, IEnumerable<T2>> ExecuteSqlReader<T1,T2>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
using (var reader = sqlCmd.ExecuteReader())
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>>(result1, result2);
protected Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>> ExecuteSqlReader<T1, T2, T3>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, Func<IDataRecord, T3> CreateObject3, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
using (var reader = sqlCmd.ExecuteReader())
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
var result3 = ExecuteReader(CreateObject3, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>>(result1, result2, result3);
protected Tuple<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>> ExecuteSqlReader<T1, T2, T3, T4>(Func<IDataRecord, T1> CreateObject1, Func<IDataRecord, T2> CreateObject2, Func<IDataRecord, T3> CreateObject3, Func<IDataRecord, T4> CreateObject4, SqlCommand sqlCmd, int commandTimeout = 30, CommandType commandType = CommandType.Text)
using (var connection = GetSqlConnection(commandTimeout, commandType, ref sqlCmd))
using (var reader = sqlCmd.ExecuteReader())
var result1 = ExecuteReader(CreateObject1, reader).ToList();
var result2 = ExecuteReader(CreateObject2, reader).ToList();
var result3 = ExecuteReader(CreateObject3, reader).ToList();
var result4 = ExecuteReader(CreateObject4, reader).ToList();
return Tuple.Create<IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>>(result1, result2, result3, result4);
private IEnumerable<T> ExecuteReader<T>(Func<IDataRecord, T> CreateObject, SqlDataReader reader)
while (reader.Read())
yield return CreateObject(reader);
reader.NextResult();
然后我就这样继承它:
public class ReviewRepo : BaseRepo
public ReviewRepo(string connectionString) : base(connectionString)
public ReviewPageableResult GetAllReviews(string productType, string serviceType, int pageNumber, int itemsPerPage, string sortBy, string sortDirection)
var parameters = new List<SqlParameter>
new SqlParameter("ProductRefDescription", productType),
new SqlParameter("ServiceRefDescription", serviceType),
new SqlParameter("ZipCodes", "NULL"),
new SqlParameter("PageNumber", pageNumber),
new SqlParameter("ItemsPerPage", itemsPerPage),
new SqlParameter("SortBy", sortBy),
new SqlParameter("SortDirection", sortDirection)
;
var cmd = new SqlCommand("dbo.GetReviews");
cmd.Parameters.AddRange(parameters.ToArray());
var results = ExecuteSqlReader(CreateReview, CreateReviewPageableResult, cmd, commandType: CommandType.StoredProcedure);
var reviewResult = results.Item2.Single();
reviewResult.Items = results.Item1;
return reviewResult;
public ReviewPageableResult GetReviewsByZip(string productType, string serviceType, string zipCodes, int pageNumber, int itemsPerPage, string sortBy, string sortDirection)
var parameters = new List<SqlParameter>
new SqlParameter("ProductRefDescription", productType),
new SqlParameter("ServiceRefDescription", serviceType),
new SqlParameter("ZipCodes", zipCodes),
new SqlParameter("PageNumber", pageNumber),
new SqlParameter("ItemsPerPage", itemsPerPage),
new SqlParameter("SortBy", sortBy),
new SqlParameter("SortDirection", sortDirection)
;
var cmd = new SqlCommand("dbo.GetReviewsByZipCodes");
cmd.Parameters.AddRange(parameters.ToArray());
var results = ExecuteSqlReader(CreateReview, CreateReviewPageableResult, cmd, commandType: CommandType.StoredProcedure);
var reviewResult = results.Item2.Single();
reviewResult.Items = results.Item1;
return reviewResult;
private Review CreateReview(IDataRecord record)
return new Review
PageReviewId = (int)record["PageReviewId"],
ProductRefId = (Guid)record["ProductRefId"],
ServiceTypeRefId = Convert.IsDBNull(record["ServiceTypeRefId"]) ? Guid.Empty : (Guid)record["ServiceTypeRefId"],
TerritoryId = Convert.IsDBNull(record["TerritoryId"]) ? Guid.Empty : (Guid)record["TerritoryId"],
FirstName = $"record["FirstName"]",
LastName = $"record["LastName"]",
City = $"record["City"]",
State = $"record["State"]",
Answer = $"record["Answer"]",
Rating =(double)record["Rating"],
SurveyDate = (DateTime)record["SurveyDate"]
;
private ReviewPageableResult CreateReviewPageableResult(IDataRecord record)
return new ReviewPageableResult
AverageRating = (double)record["AverageRating"],
Count1Stars = (int)record["Count1Stars"],
Count2Stars = (int)record["Count2Stars"],
Count3Stars = (int)record["Count3Stars"],
Count4Stars = (int)record["Count4Stars"],
Count5Stars = (int)record["Count5Stars"],
ItemsPerPage = (int)record["ItemsPerPage"],
PageNumber = (int)record["PageNumber"],
TotalCount = (int)record["TotalCount"],
;
【讨论】:
我可以看到很多代码是从一些专有解决方案中复制出来的,最终产生了 user166390 的想法 从来没有说过我写的。这是我所见过的东西的融合,加上我的一些东西,让它们一起工作。【参考方案7】:试试这个
Dim dt1, dt2, dt3As New DataTable
Dim command As SqlCommand
Dim adapter As New SqlDataAdapter
Dim ds As New DataSet
Dim Sql1, Sql2, Sql3 As String
Sql1 = "select id, CurName from Table1 where IS_Deleted=0 order by id"
Sql2 = "select id ,Item from Table2 order by id"
Sql3 = "select id ,SellPrice from Table3 order by id"
Try
conn1.Open()
command = New SqlCommand(Sql1, conn1)
command.CommandType = CommandType.Text
adapter.SelectCommand = command
adapter.Fill(ds, "dt1")
adapter.SelectCommand.CommandText = Sql2
adapter.Fill(ds, "dt2")
adapter.SelectCommand.CommandText = Sql3
adapter.Fill(ds, "dt3")
adapter.Dispose()
command.Dispose()
conn1.Close()
cmbCurrency.DataSource = ds.Tables("dt1")
cmbCurrency.DisplayMember = "CurName"
cmbCurrency.ValueMember = "id"
cmbCurrency.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
cmbGroups.DataSource = ds.Tables("dt2")
cmbGroups.DisplayMember = "Item"
cmbGroups.ValueMember = "id"
cmbGroups.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
cmbUnits.DataSource = ds.Tables("dt3")
cmbUnits.DisplayMember = "SellPrice"
cmbUnits.ValueMember = "id"
cmbUnits.SelectedIndex = -1
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''|
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
更多帮助http://vb.net-informations.com/dataset/dataset-multiple-tables-sqlserver.htm
【讨论】:
以上是关于如何使用 SqlCommand 返回多个结果集?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 SqlCommand::Execute(或替代方法)从同一存储过程中“选择 *”和“选择计数(*)”?
使用相同的 SqlConnection 对 SqlCommand.BeginExecuteNonQuery 的多个并发调用