我正在尝试使用一个存储过程来接受日期的多值参数。这不是在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如何对类似参数这样做(这是我从代码中尝试过的唯一一个),以及Date数据如何类型影响所需的格式。我收到了“从字符串转换日期和/或时间时转换失败”。选择多个值时出错。
编辑:根据要求,foreach循环输出的示例:
'9/9/2011','8/19/2011','8/12/2011'
答案 0 :(得分:10)
为什么不使用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 :(得分:3)
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);
现在你应该把你的数据作为表值。 (语法可能稍微偏离,这不在我的脑海中)