提问人:jreloz 提问时间:10/25/2023 最后编辑:Joel Coehoornjreloz 更新时间:10/25/2023 访问量:92
如何处理 T-SQL 存储过程中的多个结果集?
How to handle multiple result sets from a T-SQL stored procedure?
问:
我有一个返回多个结果集的 T-SQL 存储过程:
Select * from tbl1;
Select * from tbl2;
Select * from tbl3;
在我的 C# 代码中,我有这个:
using (SqlConnection con = new SqlConnection(_connectionString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("LIS.spData", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@ChargeId", chargeId);
using (SqlDataReader reader = cmd.ExecuteReader())
{
List<DataTable> dtList = new List<DataTable>();
while (reader.HasRows)
{
while (reader.Read())
{
DataTable tmpdt = new DataTable();
tmpdt.Load(reader);
dtList.Add(tmpdt);
}
reader.NextResult();
}
}
}
}
在我的中它说的是真的,但我不知道为什么它不在我的数据表中存储任何数据。while(reader.HasRows)
有什么建议吗?
答:
0赞
vendettamit
10/25/2023
#1
您不需要调用 ,这是在方法内部完成的。只需在调用 Load 方法之前检查读取器中是否有可用的架构即可。
这是我是如何做到的(我需要创建一个异步版本的适配器。Fill() 方法):reader.Read()
dataTable.Load(reader)
using (var reader = await command.ExecuteReaderAsync())
{
var dataSet = new DataSet();
do
{
DataTable dataTable = new DataTable();
// Check if there's a schema specified in the reader before loading it into datatable
if (reader.FieldCount > 0)
{
dataTable.Load(reader);
dataSet.Tables.Add(dataTable);
}
// No schema..Skip reading and close the reader (it will only happen in case of executing a proc that has dynamic query and it doesn't have anything to return.
if (!reader.IsClosed && reader.FieldCount == 0)
reader.Close();
}
while (!reader.IsClosed);
return dataSet;
}
评论
1赞
Joel Coehoorn
10/25/2023
这主要是很好的建议,但忽略了问题的重点(处理多个结果集)。
0赞
Albert D. Kallal
10/25/2023
#2
只需将结果发送到数据集,即可代替使用数据表。因此,您可以使用 .数据适配器的 Fill 方法。
数据集是表(数据表)的集合。
所以,说这个代码:
void LoadData()
{
DataSet HotelInfo = new DataSet();
string sConn = Properties.Settings.Default.TEST4;
using (SqlConnection conn = new SqlConnection(sConn))
{
using (SqlCommand cmdSQL = new SqlCommand("HotelInfo", conn))
{
cmdSQL.CommandType = CommandType.StoredProcedure;
cmdSQL.Parameters.Add("@Country", SqlDbType.NVarChar).Value = "Canada";
SqlDataAdapter oReader = new SqlDataAdapter(cmdSQL);
conn.Open();
oReader.Fill(HotelInfo);
}
}
// load grid of hotels
GHotels.DataSource = HotelInfo.Tables[0];
GHotels.DataBind();
GPeople.DataSource = HotelInfo.Tables[1];
GPeople.DataBind();
}
因此,存储过程可以返回任意数量的表。在此示例中,假设有 2 张桌子(酒店,并假设可能被预订到酒店的人)。
T-SQL:T-SQL:
CREATE PROCEDURE [dbo].[HotelInfo]
-- Add the parameters for the stored procedure here
@Country nvarchar(100)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT ID, City, HotelName, Description FROM tblHotelsA
WHERE Country = @Country
ORDER BY HotelName
SELECT ID, FirstName, LastName, City FROM People
ORDER BY Firstname
END
现在是标记:
<div style="float:left;width:40%">
<h3>Hotels</h3>
<asp:GridView ID="GHotels" runat="server"
CssClass="table"
>
</asp:GridView>
</div>
<div style="float:left;width:30%;margin-left:30px">
<h3>People</h3>
<asp:GridView ID="GPeople" runat="server"
CssClass="table"
>
</asp:GridView>
</div>
现在的结果是这样的:
因此,数据集只是表的集合,从存储过程返回的每个表都将成为数据集对象的表。
3赞
Joel Coehoorn
10/25/2023
#3
如果您想要的只是一个对象集合,那么切换到使用 an 到 a 的建议是正确的。(在现代 ASP.Net,早点适应也是件好事)。DataTable
SqlDataAdapter
Fill()
DataSet
async
但为了展示功能,你不需要做这些事情,使用是正确的。这里还有一些其他值得关注的事情。NextResult()
// Stack using blocks to reduce indentation
using (SqlConnection con = new(_connectionString))
using (SqlCommand cmd = new("LIS.spData", con))
{
// avoid AddWithValue()
cmd.Parameters.Add("@ChargeId", SqlDbType.Int).Value = chargeId;
cmd.CommandType = CommandType.StoredProcedure;
// wait to open the connection until the last possible moment
con.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
List<DataTable> dtList = new();
do
{
// No need to check rows or read from the DataReader to load a DataTable
DataTable tmpdt = new();
tmpdt.Load(reader);
dtList.Add(tmpdt);
} while(reader.NextResult());
}
}
下面是 DataSet 代码可能看起来的更简单版本:
// Gotta love target-typed new expressions
using (SqlConnection con = new(_connectionString))
using (SqlCommand cmd = new("LIS.spData", con))
using (SqlDataAdapter da = new(cmd))
{
cmd.Parameters.Add("@ChargeId", SqlDbType.Int).Value = chargeId;
cmd.CommandType = CommandType.StoredProcedure;
DataSet result = new();
// No need to even manually open the connection
da.Fill(result);
}
最后,我想解决这个问题:
但我不知道为什么它不在我的数据表中存储任何数据。
该变量的声明范围非常小,我想知道它是否是后来重新声明的,而不是保留的。dtList
评论
true
false