如何传递和处理 varchars 数组作为参数 to/within a SQL 服务器存储过程参数?
How can I pass and process an array of varchars as parameters to/within a SQL Server stored procedure parameter?
我使用声明这些参数的现有存储过程:
@Unit varchar(4000),
@BegDate datetime,
@EndDate datetime,
@SortBy varchar(20)
我现在面临的挑战是推导该存储过程,该存储过程采用任意数量的@Unit 参数,从 1..N
我该怎么做?是否需要将 @Unit 参数更改为 @Unit varchar(max),为参数分配定界值,然后从存储过程中解析定界值?
IOW,我需要在存储过程中做这样的事情吗:
@Unit varchar(max),
@BegDate datetime,
@EndDate datetime,
@SortBy varchar(20)
...C# 代码中的这个:
string unit = unit1 +',' + unit2 +',' + unit3 // and on for however many units are being added
. . .
sqlCommand.Parameters.AddWithValue("@Unit", unit);
...然后,返回存储过程,将逗号分隔值解析为字符串数组,并让它像这样查询 table(伪 dml):
string[] unitArray = @Unit.Split(',');
. . .
SELECT BLA, BLEE, BLOO FROM F_BUELLER WHERE Unit in unitArray[0], unitArray[1], unitArray[2], // and on for however many units are being queried for
...或what/how?
注意:如果这是一个 "normal" 项目(即非 SSRS),我将简单地使用原始存储过程,多次调用它,并合并返回的数据,按单位分组。我不知道这是否可能或如何通过 SSRS 在 rdl/xml 文件中做到这一点,但是...
更新
这里真正需要发生的是在每个唯一 "Unit" 之后有一个分页符,原因是报告导出到 Excel,并且请求者希望每个单元都在其上拥有独立的 sheet.
所以基本上我需要调用同一个存储过程 N 次,每次都自己计算结果 "page."
所以小费here似乎不错("you can create multiple datasets in Reporting Services and then use them in different elements in the report. Just add a from the Dataset: dropdown on the data tab")
问题的症结在于:如何为每个单元提供 1 个且仅提供 1 个数据集?没有办法提前知道有多少 units/sheets 会是 generated/needed;可能有几个,可能有几十个。
您可以使用 SQL 服务器 Table 类型参数。
首先在 SQL 服务器
中创建类型
CREATE TYPE [dbo].[TVP_Units]
AS TABLE(
[Units] VARCHAR(1000)
)
GO
使您的存储过程接受该类型的变量而不是 Varchar(1000) @Units 变量。
ALTER PROCEDURE MyProc
@TVP_Units [dbo].[TVP_Units] READONLY
, @BegDate datetime
, @EndDate datetime
, @SortBy varchar(20)
....... rest of the code
我不是 C# 的期望,但你的 C# 代码看起来像....
using (con)
{
//Create a DataTable ....
DataTable _dt = new DataTable("Units");
_dt.Columns.Add("Unit", typeof(string));
_dt.Rows.Add("Unit 1");
_dt.Rows.Add("Unit 2");
_dt.Rows.Add("Unit 3");
SqlCommand sqlCmd = new SqlCommand("dbo.MyProc", con);
sqlCmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = sqlCmd.Parameters.AddWithValue("@TVP_Units", _dt);
//tells ado.net it is a TVP
tvpParam.SqlDbType = SqlDbType.Structured;
sqlCmd.Parameters.AddWithValue("@BegDate", YourC#Param);
sqlCmd.Parameters.AddWithValue("@EndDate", YourC#Param);
sqlCmd.Parameters.AddWithValue("@SortBy", YourC#Param);
con.Open();
sqlCmd.ExecuteNonQuery();
}
我这样做的方法是传入一个分隔字符串作为报告参数。
在报告中构建一个数据集,使用 XML 转换将分隔的字符串分解成行。假设当值超过 1 个时 @Unit 参数以逗号分隔,数据集查询将如下所示:
DECLARE @UnitXml XML = CAST('<unit>' + REPLACE(@Unit,',','</unit><unit>') + '</unit>' AS XML)
SELECT unit.x.value('.','VARCHAR(200)') AS [unit]
FROM @UnitXml.nodes('/unit') AS unit(x)
然后制作一个 tablix,其中包含数据集中每个项目的一行。
在tablix 的行组中放置一个子报表。在您的情况下,子报表将指向一个报表部分,显示一个单元的所有信息,并将单元号从数据集传递到您的存储过程。
存储过程将为每个单元 运行 一次。我意识到这既不优雅也不高效,但这是 SSRS。
我使用声明这些参数的现有存储过程:
@Unit varchar(4000),
@BegDate datetime,
@EndDate datetime,
@SortBy varchar(20)
我现在面临的挑战是推导该存储过程,该存储过程采用任意数量的@Unit 参数,从 1..N
我该怎么做?是否需要将 @Unit 参数更改为 @Unit varchar(max),为参数分配定界值,然后从存储过程中解析定界值?
IOW,我需要在存储过程中做这样的事情吗:
@Unit varchar(max),
@BegDate datetime,
@EndDate datetime,
@SortBy varchar(20)
...C# 代码中的这个:
string unit = unit1 +',' + unit2 +',' + unit3 // and on for however many units are being added
. . .
sqlCommand.Parameters.AddWithValue("@Unit", unit);
...然后,返回存储过程,将逗号分隔值解析为字符串数组,并让它像这样查询 table(伪 dml):
string[] unitArray = @Unit.Split(',');
. . .
SELECT BLA, BLEE, BLOO FROM F_BUELLER WHERE Unit in unitArray[0], unitArray[1], unitArray[2], // and on for however many units are being queried for
...或what/how?
注意:如果这是一个 "normal" 项目(即非 SSRS),我将简单地使用原始存储过程,多次调用它,并合并返回的数据,按单位分组。我不知道这是否可能或如何通过 SSRS 在 rdl/xml 文件中做到这一点,但是...
更新
这里真正需要发生的是在每个唯一 "Unit" 之后有一个分页符,原因是报告导出到 Excel,并且请求者希望每个单元都在其上拥有独立的 sheet.
所以基本上我需要调用同一个存储过程 N 次,每次都自己计算结果 "page."
所以小费here似乎不错("you can create multiple datasets in Reporting Services and then use them in different elements in the report. Just add a from the Dataset: dropdown on the data tab")
问题的症结在于:如何为每个单元提供 1 个且仅提供 1 个数据集?没有办法提前知道有多少 units/sheets 会是 generated/needed;可能有几个,可能有几十个。
您可以使用 SQL 服务器 Table 类型参数。
首先在 SQL 服务器
中创建类型CREATE TYPE [dbo].[TVP_Units]
AS TABLE(
[Units] VARCHAR(1000)
)
GO
使您的存储过程接受该类型的变量而不是 Varchar(1000) @Units 变量。
ALTER PROCEDURE MyProc
@TVP_Units [dbo].[TVP_Units] READONLY
, @BegDate datetime
, @EndDate datetime
, @SortBy varchar(20)
....... rest of the code
我不是 C# 的期望,但你的 C# 代码看起来像....
using (con)
{
//Create a DataTable ....
DataTable _dt = new DataTable("Units");
_dt.Columns.Add("Unit", typeof(string));
_dt.Rows.Add("Unit 1");
_dt.Rows.Add("Unit 2");
_dt.Rows.Add("Unit 3");
SqlCommand sqlCmd = new SqlCommand("dbo.MyProc", con);
sqlCmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvpParam = sqlCmd.Parameters.AddWithValue("@TVP_Units", _dt);
//tells ado.net it is a TVP
tvpParam.SqlDbType = SqlDbType.Structured;
sqlCmd.Parameters.AddWithValue("@BegDate", YourC#Param);
sqlCmd.Parameters.AddWithValue("@EndDate", YourC#Param);
sqlCmd.Parameters.AddWithValue("@SortBy", YourC#Param);
con.Open();
sqlCmd.ExecuteNonQuery();
}
我这样做的方法是传入一个分隔字符串作为报告参数。
在报告中构建一个数据集,使用 XML 转换将分隔的字符串分解成行。假设当值超过 1 个时 @Unit 参数以逗号分隔,数据集查询将如下所示:
DECLARE @UnitXml XML = CAST('<unit>' + REPLACE(@Unit,',','</unit><unit>') + '</unit>' AS XML)
SELECT unit.x.value('.','VARCHAR(200)') AS [unit]
FROM @UnitXml.nodes('/unit') AS unit(x)
然后制作一个 tablix,其中包含数据集中每个项目的一行。
在tablix 的行组中放置一个子报表。在您的情况下,子报表将指向一个报表部分,显示一个单元的所有信息,并将单元号从数据集传递到您的存储过程。
存储过程将为每个单元 运行 一次。我意识到这既不优雅也不高效,但这是 SSRS。