Tsql 动态SQL中的减法

Tsql 动态SQL中的减法,tsql,dynamic-sql,Tsql,Dynamic Sql,我正在更新一个存储过程,以将报告时间更改为客户端时区。存储过程由动态SQL组成,其中包含smallint数据类型的time@timeoffset参数 DECLARE @sql VARCHAR(MAX) = N'SELECT DISTINCT cl.ClientId, CASE WHEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+', x.changedate) >= '''+ CONVERT(varchar, @start_da

我正在更新一个存储过程,以将报告时间更改为客户端时区。存储过程由动态SQL组成,其中包含smallint数据类型的time@timeoffset参数

  DECLARE @sql VARCHAR(MAX) = 
  N'SELECT DISTINCT cl.ClientId, 
  CASE WHEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+', x.changedate) >= '''+ CONVERT(varchar, @start_date) +''' 
  AND DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+', x.changedate) < '''+ CONVERT(varchar, @end_date_plus1) +''' 
  THEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+',x.changedate)' 
DECLARE@sql VARCHAR(MAX)=
N'SELECT DISTINCT cl.ClientId,
DATEADD(HOUR,“+CONVERT(CHAR(2),@timeoffset)+',x.changedate)>=''时的大小写+转换(varchar,@start_date)+''
和DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+',x.changedate)<'+CONVERT(varchar,@end\u date\u plus1)+''
然后是DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)+',x.changedate)'
要更改客户端时区的时间,我需要减去@timeoffset。将其设为负值不会改变输出。 尝试在转换之前添加(-)将引发错误,因为减法运算符对varchar无效。写它 如果不进行转换,则会引发错误 '将nvarchar值转换为数据类型smallint时,转换失败


有人能帮我吗?谢谢

您可以尝试将负数作为另一个变量传递:

DECLARE @neg INT = -1;
DECLARE @sql VARCHAR(MAX) = 
N'SELECT DISTINCT cl.ClientId, 
CASE WHEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+', x.changedate) >= '''+ 
CONVERT(varchar, @start_date) +''' 
AND DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+', x.changedate) < '''+ 
CONVERT(varchar, @end_date_plus1) +''' 
THEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+',x.changedate)' 
DECLARE@neg INT=-1;
声明@sql VARCHAR(最大值)=
N'SELECT DISTINCT cl.ClientId,
DATEADD(HOUR,“+CONVERT(CHAR(2),@timeoffset)*@neg+',x.changedate)>=”时的大小写
转换(varchar,@start_date)+''
和DATEADD(小时,+CONVERT(字符(2),@timeoffset)*@neg+,x.changedate)<'+
转换(varchar,@end\u date\u plus1)+''
然后添加日期(小时,+CONVERT(字符(2),@timeoffset)*@neg+',x.changedate)'

您可以尝试将负数作为另一个变量传递:

DECLARE @neg INT = -1;
DECLARE @sql VARCHAR(MAX) = 
N'SELECT DISTINCT cl.ClientId, 
CASE WHEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+', x.changedate) >= '''+ 
CONVERT(varchar, @start_date) +''' 
AND DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+', x.changedate) < '''+ 
CONVERT(varchar, @end_date_plus1) +''' 
THEN DATEADD(HOUR,'+CONVERT(CHAR(2),@timeoffset)*@neg+',x.changedate)' 
DECLARE@neg INT=-1;
声明@sql VARCHAR(最大值)=
N'SELECT DISTINCT cl.ClientId,
DATEADD(HOUR,“+CONVERT(CHAR(2),@timeoffset)*@neg+',x.changedate)>=”时的大小写
转换(varchar,@start_date)+''
和DATEADD(小时,+CONVERT(字符(2),@timeoffset)*@neg+,x.changedate)<'+
转换(varchar,@end\u date\u plus1)+''
然后添加日期(小时,+CONVERT(字符(2),@timeoffset)*@neg+',x.changedate)'

我注意到您发布的代码中存在一些问题:

  • 您正在将
    @Sql
    声明为
    varchar(max)
    ,但在设置其值之前使用了
    N
    前缀。您只需要在处理unicode数据时使用它(
    nchar
    nvarcar
    )。这很关键,但您应该意识到这一点

  • 您正在使用
    convert
    ,但未指定
    样式
    参数。将整型转换为字符串并没有那么糟糕,但在处理日期时可能会导致意外行为。无论何时需要对日期/日期时间值使用字符串表示,都应始终使用ISO8601标准,因为它保证Sql server始终将其正确转换为日期,而不管本地设置如何。要将
    datetime
    值转换为ISO8061标准,请在
    convert
    语句中使用样式126

  • 您正在使用
    varchar
    ,但未指定长度。这是一个坏习惯,因为SQL Server根据上下文的不同对长度有不同的默认值。声明变量时为1,但在
    cast
    convert
    中使用时为30

  • 我对您的代码做了一些更改,包括更改
    @timeoffset
    参数的
    char(2)
    (因为11个char甚至会包含int数据类型的最小值-2147483648),并且没有任何问题

    这是我的测试:

    DECLARE @timeOffset int = -10, 
            @start_date datetime = getdate(), 
            @sql nvarchar(max)
    
    SET @sql = 
    N'SELECT '''+ convert(char(23), @start_date, 126) +''' As GetDate, 
           DATEADD(HOUR, '+ CAST(@timeOffset as varchar(11)) +', '''+ convert(char(23), @start_date, 126) +''') As DateAdd';
    
    SELECT @Sql
    
    EXEC(@sql)
    
    结果:

    SELECT '2018-11-08T20:33:31.670' As GetDate, 
           DATEADD(HOUR, -10, '2018-11-08T20:33:31.670') As DateAdd
    
    GetDate                     DateAdd
    2018-11-08T20:33:31.670     08.11.2018 10:33:3
    

    我注意到您发布的代码中存在一些问题:

  • 您正在将
    @Sql
    声明为
    varchar(max)
    ,但在设置其值之前使用了
    N
    前缀。您只需要在处理unicode数据时使用它(
    nchar
    nvarcar
    )。这很关键,但您应该意识到这一点

  • 您正在使用
    convert
    ,但未指定
    样式
    参数。将整型转换为字符串并没有那么糟糕,但在处理日期时可能会导致意外行为。无论何时需要对日期/日期时间值使用字符串表示,都应始终使用ISO8601标准,因为它保证Sql server始终将其正确转换为日期,而不管本地设置如何。要将
    datetime
    值转换为ISO8061标准,请在
    convert
    语句中使用样式126

  • 您正在使用
    varchar
    ,但未指定长度。这是一个坏习惯,因为SQL Server根据上下文的不同对长度有不同的默认值。声明变量时为1,但在
    cast
    convert
    中使用时为30

  • 我对您的代码做了一些更改,包括更改
    @timeoffset
    参数的
    char(2)
    (因为11个char甚至会包含int数据类型的最小值-2147483648),并且没有任何问题

    这是我的测试:

    DECLARE @timeOffset int = -10, 
            @start_date datetime = getdate(), 
            @sql nvarchar(max)
    
    SET @sql = 
    N'SELECT '''+ convert(char(23), @start_date, 126) +''' As GetDate, 
           DATEADD(HOUR, '+ CAST(@timeOffset as varchar(11)) +', '''+ convert(char(23), @start_date, 126) +''') As DateAdd';
    
    SELECT @Sql
    
    EXEC(@sql)
    
    结果:

    SELECT '2018-11-08T20:33:31.670' As GetDate, 
           DATEADD(HOUR, -10, '2018-11-08T20:33:31.670') As DateAdd
    
    GetDate                     DateAdd
    2018-11-08T20:33:31.670     08.11.2018 10:33:3
    

    您是否检查了带有CHAR(2)的部分,@timeoffset,它似乎只显示@t,因此该值为null,因为它没有声明。是的,它包含整个部分。当我省略转换时,它会要求声明@timeoffset,上面已经声明了@timeoffset。你能在计算时粘贴@sql的整个输出吗?问题中提供的代码可以在没有动态sql的情况下编写。在这种情况下,是否有充分的理由使用动态SQL?当然。这是因为来源。客户机具有特定的数据库,并且从相应的数据库检索数据。为了简单起见,我只共享了select语句的一部分。您是否用CHAR(2)检查了该部分,@timeoffset,它似乎只出现了@t,因此该值为null,因为它没有声明。是的,它包含整个部分。当我省略convert时,它要求dec