【问题标题】:Multi-value date parameter in stored procedure?存储过程中的多值日期参数?
【发布时间】:2011-11-21 04:54:50
【问题描述】:

我正在尝试让一个接受多值日期参数的存储过程工作。这不在 SSRS 中,但我正在尝试使用与它相同的方法:

ALTER PROCEDURE spSelectPlacementData
(
    @ClientID           SMALLINT,
    @SourceFileDates    VARCHAR(MAX)
)
AS
BEGIN
    SELECT (snip)
    FROM [APS].[dbo].[Account] A
    WHERE ClientID = @ClientID
    AND A.[SourceFileDate] IN (SELECT * FROM dbo.Split(@SourceFileDates))
END

我将此方法与 SSRS 报告多值参数上的 INT 和 VARCHAR 字段一起使用。

这是我用来连接 SourceFileDates 的代码:

    string sourceFileDates = "";

    foreach (DateTime file in job.sourceFiles)
    {
        if (file == job.sourceFiles.Last())
        {
            sourceFileDates += "'" + file.ToString("d") + "'";
        }
        else
        {
            sourceFileDates += "'" + file.ToString("d") + "', ";
        }
    }

    selectRunCommand = new SqlCommand("spSelectPlacementData", sqlConnection);
    selectRunCommand.CommandType = CommandType.StoredProcedure;
    selectRunCommand.Parameters.Add("@ClientID", SqlDbType.SmallInt);
    selectRunCommand.Parameters["@ClientID"].Value = job.clientID;
    selectRunCommand.Parameters.Add("@SourceFileDates", SqlDbType.VarChar);
    selectRunCommand.Parameters["@SourceFileDates"].Value = sourceFileDates;

使用我在网上抓到的这个 dbo.Split 函数:

/****** Object:  UserDefinedFunction [dbo].[Split]    Script Date: 09/20/2011 11:16:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[Split]
/* This function is used to split up multi-value parameters */
(
@ItemList VARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @IDTable TABLE (Item VARCHAR(MAX) collate database_default )
AS
BEGIN
DECLARE @tempItemList VARCHAR(MAX)
SET @tempItemList = @ItemList

DECLARE @i INT
DECLARE @Item VARCHAR(MAX)

SET @tempItemList = REPLACE (@tempItemList, @delimiter + ' ', @delimiter)
SET @i = CHARINDEX(@delimiter, @tempItemList)

WHILE (LEN(@tempItemList) > 0)
BEGIN
IF @i = 0
SET @Item = @tempItemList
ELSE
SET @Item = LEFT(@tempItemList, @i - 1)

INSERT INTO @IDTable(Item) VALUES(@Item)

IF @i = 0
SET @tempItemList = ''
ELSE
SET @tempItemList = RIGHT(@tempItemList, LEN(@tempItemList) - @i)

SET @i = CHARINDEX(@delimiter, @tempItemList)
END
RETURN
END

我想我并不完全清楚我格式化参数的方式、SSRS 如何处理类似参数(这是我尝试从代码中做的唯一一个)以及日期数据的不同之处类型会影响所需的格式。我收到“从字符串转换日期和/或时间时转换失败。”选择多个值时出错。

编辑:根据要求,foreach 循环输出示例:

“2011 年 9 月 9 日”、“2011 年 8 月 19 日”、“2011 年 8 月 12 日”

【问题讨论】:

  • 在foreach循环后显示sourceFileDates的值

标签: c# tsql sql-server-2008 stored-procedures parameters


【解决方案1】:

为什么不使用Table-Valued parameter?

在 SQL 上创建用户定义的表类型DateTimes

create type DateTimes as table
(
    [Value] datetime
)

然后修改你的存储过程:

ALTER PROCEDURE spSelectPlacementData
(
    @ClientID           SMALLINT,
    @SourceFileDates    DateTimes readonly -- must be readonly
)

现在您可以将@SourceFileDates 视为只读表变量。

指定SqlCommand 参数时,表值参数指定为SqlDbType.Structured,并作为DataTable 或DataRowcollection 传递。所以,你可以像这样填充它:

var sourceFileDates = new DataTable();
sourceFileDates.Columns.Add("Value", typeof(DateTime));
foreach (DateTime file in job.sourceFiles)
{
    sourceFileDates.Rows.Add(file);
}
selectRunCommand.Parameters.Add(new SqlParameter {
    ParameterName = "@SourceFileDates", 
    Value = sourceFileDates,
    SqlDbType = SqlDbType.Structured // make sure you specify structured
});

现在一切都很好并且输入正确......您不必进行任何字符串解析或转换。

作为旁注,您不妨继续创建Strings 和Integers 类型;你会迷上 TVP 并在各处使用它们。

【讨论】:

  • 这听起来正是我正在寻找的东西,我不知道这些存在。我试试看,谢谢!
  • 非常好的实现和解释。我会尽快 +1(今天没有投票)。
  • 我不是在反对,我是在做笔记……对于 OP,您的回答是一个完全合法且优雅的解决方案。但是,如果有人在谷歌上搜索类似的东西,可能会因为它在 2005 年的系统上不起作用而感到沮丧。
【解决方案2】:

SSRS 有点作弊,因为它控制输入......它不太关心 SQL 注入攻击。通过存储过程,这会有点困难。

当我在 2005 年需要在一个参数中发送多个值时,什么对我很有效,我会像这样将它们作为 XML 字符串发送:

<dates>
    <date>2011-01-23</date>
    <date>2011-02-24</date>
</dates>

然后把它当作函数中的一个表:

select 
    x.a.value('.', 'datetime') as myDate
from
    @XMLArg.nodes('/dates/date') x(a);

现在您应该将数据作为表值。 (语法可能有点不对劲,这不是我的想法)

【讨论】:

    猜你喜欢
    • 2016-05-13
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 2019-08-14
    • 1970-01-01
    相关资源
    最近更新 更多