【问题标题】:How can I pass and process an array of varchars as parameters to/within a SQL Server stored procedure parameter?如何将 varchars 数组作为参数传递和处理到 SQL Server 存储过程参数/在 SQL Server 存储过程参数中?
【发布时间】:2016-09-25 02:58:11
【问题描述】:

我使用声明这些参数的现有存储过程:

@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);

...然后,回到存储过程中,将逗号分隔的值解析为字符串数组并让它像这样查询表(伪 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

...或什么/如何?

注意:如果这是一个“普通”项目(即非 SSRS),我会简单地使用原始存储过程,多次调用它,然后合并返回的数据,按 Unit 分组。我不知道这是否可能或如何在 rdl/xml 文件中从 SSRS 执行此操作...

更新

这里真正需要发生的是,在每个唯一的“单元”之后有一个分页符,原因是报告被导出到 Excel,请求者希望每个单元在自己的单独工作表中。

所以基本上我需要调用同一个存储过程 N 次,每次都将结果放在它自己的“页面”上。

所以提示here 似乎不错(“您可以在 Reporting Services 中创建多个数据集,然后在报表中的不同元素中使用它们。只需从数据集:数据选项卡上的下拉列表中添加一个”)

不过,饼干的关键是:如何为每个单元提供 1 个且仅 1 个数据集?无法提前知道将生成/需要多少个单元/工作表;可能有几个,可能有几十个。

【问题讨论】:

    标签: sql-server stored-procedures reporting-services parameter-passing dml


    【解决方案1】:

    您可以使用 SQL Server 表类型参数。

    首先在 SQL Server 中创建一个类型

    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();
     }
    

    【讨论】:

    • 我希望它是 C#,我对它感到满意(也不是真正的专家),但我需要在 SSRS / rdl 文件中执行此操作。
    • 99% 确定 SSRS 不会接受用户定义的表值类型参数。至少我无法让它工作。
    【解决方案2】:

    我这样做的方法是传入一个分隔字符串作为报告参数。

    在报表中构建一个数据集,该数据集使用 XML 转换将分隔字符串分解为行。假设@Unit 参数在超过 1 个值时以逗号分隔,则数据集查询将如下所示:

    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。

    【讨论】:

    • 我对此有点困惑,因为 (a) 有人否决了它(我投了赞成票以使其恢复为 0);我不知道否决票是否有效 - 如果是,这种方法有什么问题? (b) 我只是 SSRS 中的一个偶尔涉猎者(根据需要),所以需要更多细节来确定这个答案的正面或反面——在这一点上,对我来说这几乎就像“巫毒编程”。
    • 这篇文章解释了添加子报表:stackoverflow.com/questions/24744728/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-18
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    相关资源
    最近更新 更多