存储过程中的多值日期参数?
我正在尝试使用一个存储过程来接受日期的多值参数。 这不是在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.Splitfunction我在网上抓了:
/****** 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’
为什么不使用Table-Valued参数 ?
在SQL上创建用户定义的表类型DateTimes
create type DateTimes as table ( [Value] datetime )
然后修改您的存储过程:
ALTER PROCEDURE spSelectPlacementData ( @ClientID SMALLINT, @SourceFileDates DateTimes readonly -- must be readonly )
现在,您可以将@SourceFileDates
视为只读表变量。
指定SqlCommand
参数时,Table-Valued参数指定为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并在整个地方使用它们。
SSRS有点欺骗,因为它控制着输入…它并不是那么关心SQL注入攻击。 通过存储过程,这将更难做到。
当我需要在2005年在一个参数中发送多个值时,对我来说效果很好,我会将它们作为XML字符串发送,如下所示:
2011-01-23 2011-02-24
然后将其视为函数中的表:
select xavalue('.', 'datetime') as myDate from @XMLArg.nodes('/dates/date') x(a);
现在你应该把你的数据作为表值。 (语法可能有点偏,这不是我的头脑)