2

下面我有一段来自我试图动态化的存储过程的代码。这意味着我想运行EXEC('select * from table_name WHERE filter=something')以将结果集返回到我的 Web 服务。我正在查询的表中的 week_start_date 字段是日期时间字段,而不是日期字段。如何正确地将 datetime 参数附加到动态 SQL,以便它在查询中正确解释它?另外,如果您对如何使代码更清洁有任何建议,我会接受建议。

当我查看数据时,我的值如下所示:

2012-08-10 00:00:00.000

不工作的 T-SQL 代码:

ALTER PROCEDURE [dbo].[logged_time_by_week]
    @week_start_date_filter datetime = null
AS
BEGIN

……

    DECLARE @select_clause nvarchar(4000);
    DECLARE @from_clause nvarchar(4000);
    DECLARE @where_clause nvarchar(4000);
    DECLARE @order_clause nvarchar(4000);

    SET @select_clause = 
        ' SELECT '
        + ' [sunday_hours],'
        + ' [monday_hours],'
        + ' [tuesday_hours],'
        + ' [wednesday_hours],'
        + ' [thursday_hours],'
        + ' [friday_hours],'
        + ' [saturday_hours]'

    SET @from_clause =
        ' FROM '
        + ' [timesheet_row] '

    SET @where_clause = ''

    IF @week_start_date_filter IS NOT NULL AND @week_start_date_filter != ''
    BEGIN 
        IF @where_clause != ''
        BEGIN
            SET @where_clause = @where_clause + ' AND ' 
        END
        SET @where_clause = @where_clause + ' [week_start_date] = ' + CONVERT(nvarchar, @week_start_date_filter)
    END

    IF @where_clause != '' 
    BEGIN
        SET @where_clause = ' WHERE ' + @where_clause
    END

    SET @order_clause = ' ORDER BY [' + @sort_column + '] ' + @sort_direction

    EXEC(@select_clause + @from_clause + @where_clause + @order_clause)
4

3 回答 3

3

我认为这应该让你走上正确的道路:

declare @dtValue datetime = '2012-10-02 15:34:53'
declare @CRLF    char(2)  = char(0x0D) + char(0x0A)
declare @QT1     char(1)  = ''''
declare @dtFrom  datetime      = convert(date,@dtValue,112)
declare @dtThru  datetime      = dateadd(ms,-3,dateadd(day,1,@dtFrom))
declare @sql     varchar(8000)

select @sql = 'select *'            + @CRLF
            + 'from sys.objects so' + @CRLF
            + 'where so.create_date between '
            + quotename( convert(varchar,@dtFrom,126) , @QT1 )
            + ' and '
            + quotename( convert(varchar,@dtThru,126) , @QT1 )

select sqlCommand = @sql

exec ( @sql )

上面的代码会生成这个sql:

select *
from sys.objects so
where so.create_date between '2012-10-02T00:00:00' and '2012-10-02T23:59:59.997'

奇怪的上限是由于 SQL Server 奇怪的时间概念,其中一分钟的最后一个“滴答”是 997 毫秒,任何大于该值的毫秒值都会向上舍入到下一分钟(所以 2012 年 10 月 2 日 23:59:59.999实际上是 2012 年 10 月 3 日 00:00:00.000)。

于 2012-10-09T18:14:34.233 回答
3

解决此类错误的最简单方法是打印生成的 sql 以查看其失败的原因。

只需查看您的查询,我相信您只需要修复 @week_start_date_filter 变量周围的引号。

declare @week_start_date_filter datetime = getdate();
print ' [week_start_date] = ''' + CONVERT(nvarchar, @week_start_date_filter) + '''';

另外作为旁注,如果您必须使用动态 sql,我建议改为使用参数化 sql。这是一个使用 sys.objects 的示例,因为我不知道您的表的架构。

DECLARE
    @week_start_date_filter datetime    = (SELECT TOP(1) [create_date] FROM sys.objects),
    @sort_column            sysname     = N'create_date',
    @sort_direction         nvarchar(3) = N'ASC';


    DECLARE @select_clause nvarchar(4000);
    DECLARE @from_clause nvarchar(4000);
    DECLARE @where_clause nvarchar(4000);
    DECLARE @order_clause nvarchar(4000);

    SET @select_clause = 
        ' SELECT TOP(1) '
        + ' *';

    SET @from_clause =
        ' FROM '
        + ' sys.objects'

    SET @where_clause = ''

    IF @week_start_date_filter IS NOT NULL AND @week_start_date_filter != ''
    BEGIN 
        IF @where_clause != ''
        BEGIN
            SET @where_clause = @where_clause + ' AND ' 
        END
        SET @where_clause = @where_clause + ' [create_date] = @date_filter'
    END

    IF @where_clause != '' 
    BEGIN
        SET @where_clause = ' WHERE ' + @where_clause
    END

    SET @order_clause = ' ORDER BY [' + @sort_column + '] ' + @sort_direction

    DECLARE
        @SQL    nvarchar(max) = @select_clause + @from_clause + @where_clause + @order_clause,
        @Params nvarchar(200) = N'@date_filter datetime';


    EXEC sp_executesql
        @stmt        = @SQL,
        @params      = @Params,
        @date_filter = @week_start_date_filter;
于 2012-10-09T17:56:16.667 回答
2

我认为这应该适用于 where 子句..

SET @where_clause = @where_clause + 
' [week_start_date] = CONVERT(datetime, ' + @week_start_date_filter + ')'

如果你的 week_start_date 列不是日期时间类型,那么它也需要像上面那样转换..

于 2012-10-09T18:20:06.123 回答