日期超出范围但仅限于存储过程调用

时间:2017-10-16 10:26:30

标签: sql sql-server-2008 tsql

我正在尝试在查询中将DATETIME字段转换为dd-mm-yyyy格式。

当我在SSMS中运行以下任一行时,查询会成功执行,我会以正确的格式获取日期。

CONVERT(VARCHAR(30), CONVERT(DATETIME, f.Created, 101), 103) as [Created]
CONVERT(VARCHAR, f.created, 105) as [Created]

f.Created是DATETIME列

但是,如果我尝试在存储过程中将其作为查询的一部分运行,我会收到错误:

The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.

在存储过程中,我尝试将语言设置为British,并将日期格式设置为dmy但我仍然会出现超出范围的错误。如果我删除这些行或只是正常选择f.Created字段,它就可以正常工作。

出了什么问题?

编辑:

查询以运行SP

DECLARE @html nvarchar(MAX);
EXEC spQueryToHtmlTable @html = @html OUTPUT,  @query = N'

 SELECT top 100 * from 
  (
      select 
      c.clno + ''.'' + f.fileno as [Number]
      ,c.clName as [Client Name]
      ,f.fileDesc as [File name]
      ,CONVERT(VARCHAR(255), f.created, 105) as Created_ddmmyyyy
      --Or either of these: 
      --CONVERT(VARCHAR(30), CONVERT(DATETIME, f.Created, 101), 103) as [Created]
      --CONVERT(VARCHAR, f.created, 105) as [Created]
      from config.dbfile f
      join config.dbclient c on c.clid = f.clid
  ) x
  where x.Department = ''Import'' and Type = ''Import''
  and 
x.Created_ddmmyyyy Between DATEADD(m, -2, GETDATE()) and GETDATE()

', @orderBy = '';

EXEC msdb.dbo.sp_send_dbmail
    @profile_name = 'Outlook',
    @recipients = 'email@email.com;',
    @subject = 'subject of email',
    @body = @html,
    @body_format = 'HTML',
    @query_no_truncate = 1,
    @attach_query_result_as_file = 0;  

SP:

/****** Object:  StoredProcedure [dbo].[spQueryToHtmlTable]    Script Date: 10/16/2017 11:47:40 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

-- Description: Turns a query into a formatted HTML table. Useful for emails. 
-- Any ORDER BY clause needs to be passed in the separate ORDER BY parameter.
-- =============================================
CREATE PROC [dbo].[spQueryToHtmlTable] 
(
  @query nvarchar(MAX), --A query to turn into HTML format. It should not include an ORDER BY clause.
  @orderBy nvarchar(MAX) = NULL, --An optional ORDER BY clause. It should contain the words 'ORDER BY'.
  @html nvarchar(MAX) = NULL OUTPUT --The HTML output of the procedure.
)
AS
BEGIN   
  SET NOCOUNT ON;

  IF @orderBy IS NULL BEGIN
    SET @orderBy = ''  
  END

  SET @orderBy = REPLACE(@orderBy, '''', '''''');

  DECLARE @realQuery nvarchar(MAX) = '
    DECLARE @headerRow nvarchar(MAX);
    DECLARE @cols nvarchar(MAX);    

    SELECT * INTO #dynSql FROM (' + @query + ') sub;

    SELECT @cols = COALESCE(@cols + '', '''''''', '', '''') + ''['' + name + ''] AS ''''td''''''
    FROM tempdb.sys.columns 
    WHERE object_id = object_id(''tempdb..#dynSql'')
    ORDER BY column_id;

    SET @cols = ''SET @html = CAST(( SELECT '' + @cols + '' FROM #dynSql ' + @orderBy + ' FOR XML PATH(''''tr''''), ELEMENTS XSINIL) AS nvarchar(max))''    

    EXEC sys.sp_executesql @cols, N''@html nvarchar(MAX) OUTPUT'', @html=@html OUTPUT

    SELECT @headerRow = COALESCE(@headerRow + '''', '''') + ''<th>'' + name + ''</th>'' 
    FROM tempdb.sys.columns 
    WHERE object_id = object_id(''tempdb..#dynSql'')
    ORDER BY column_id;

    SET @headerRow = ''<tr>'' + @headerRow + ''</tr>'';

    SET @html = ''<table border="1">'' + @headerRow + @html + ''</table>'';    
    ';

  EXEC sys.sp_executesql @realQuery, N'@html nvarchar(MAX) OUTPUT', @html=@html OUTPUT
END

GO

f.created column中的典型数据

2002-11-05 00:00:00.000
2003-12-15 00:00:00.000
2002-11-05 00:00:00.000
2002-11-05 00:00:00.000
2002-11-06 00:00:00.000

f.Created列的预期结果

05-11-2002
15-12-2003
05-11-2002
05-11-2002
06-11-2002

我会对dd-mm-yy / yyyy

的任何变化感到满意

3 个答案:

答案 0 :(得分:1)

第一个查询的WHERE条件中出现错误

WHERE
x.Created_ddmmyyyy Between DATEADD(m, -2, GETDATE()) and GETDATE()

因为您已将DATETIME转换为字符串,然后尝试将该字符串与其他两个日期进行比较(BETWEEN)

只需在子查询中移动此条件,并在WHERE中使用原始DATETIME列,并在SELECT ..中转换。

实际上为什么你甚至使用子查询:

@query = N'
select top 100
  c.clno + ''.'' + f.fileno as [Number]
  ,c.clName as [Client Name]
  ,f.fileDesc as [File name]
  ,CONVERT(VARCHAR(255), f.created, 105) as Created
from config.dbfile f
join config.dbclient c on c.clid = f.clid
where Department = ''Import'' 
and Type = ''Import''
and f.Created Between DATEADD(m, -2, GETDATE()) and GETDATE()'

或者有两列 - 一个在WHERE中使用的原始DATETIME,另一个转换为VARCHAR以显示给客户端。

答案 1 :(得分:0)

正确的方法就是:

CONVERT(VARCHAR(255), f.created, 105) as [Created]

您应该始终在SQL Server中包含字符串类型的长度。  但是,这不会解决您的问题。一个问题可能是命名约定。我不知道您的存储过程是什么样的,但您可以尝试:

CONVERT(VARCHAR(255), f.created, 105) as Created_ddmmyyyy

这样,两人不会混淆。如果Created_ddmmyyyy被用于某种目的,您的查询可能会尝试将其转换回日期/时间 - 使用不同的格式。

您不应该在将日期/时间转换为字符串时出现超出范围的错误。

答案 2 :(得分:0)

如果已经采用日期时间格式,则根本不要转换f.created列。 dateadd()返回一个日期时间,与列的类型完全匹配。

SELECT top 100 * from 
  (
      select 
      c.clno + '.' + f.fileno as [Number]
      ,c.clName as [Client Name]
      ,f.fileDesc as [File name]
      ,f.created
      --,CONVERT(VARCHAR(255), f.created, 105) as Created_ddmmyyyy
      from config.dbfile f
      join config.dbclient c on c.clid = f.clid
  ) x
  where x.Department = 'Import' and Type = 'Import'
  and x.Created >= DATEADD(m, -2, GETDATE())
  and x.Created < GETDATE()

我能想到你为什么添加转换的唯一原因是因为你已经读过getdate()包含时间组件的某个地方,你希望昨天返回的结果减去2个月直到今天,而不是&#34;现在&#34;减去2个月直到&#34;现在&#34; (即包括时间)。如果是这种情况,您可能会被互联网上发现的许多不正确的例子之一误入歧途。忘记转换成字符串,只需使用dateadd()和datediff()的智能组合,如果没有您现在体验的国际日期格式噩梦,并且作为额外的奖励,您将得到您所需要的内容:它更快。如果您想充分了解情况,请阅读:Dwain Camps' blog post called "Manipulating Dates and Times in T-SQL"。但这是一个快速示例,它实现了日期截断,以消除getdate()返回的时间组件。

 SELECT top 100 * from 
  (
      select 
      c.clno + '.' + f.fileno as [Number]
      ,c.clName as [Client Name]
      ,f.fileDesc as [File name]
      ,f.created
      --,CONVERT(VARCHAR(255), f.created, 105) as Created_ddmmyyyy
      from config.dbfile f
      join config.dbclient c on c.clid = f.clid
  ) x
  where x.Department = 'Import' and Type = 'Import'
  and x.Created >= DATEADD(m, -2, dateadd(d, datediff(d, 0, GETDATE()), 0))
  and x.Created < dateadd(d, datediff(d, 0, GETDATE()), 0)

请注意使用&gt; =和&lt;而不是在我的例子之间。 Between包括开始值和结束值,因此如果使用between而不是=&gt;,则可能错误地包含时间分量为00:00:00.000的行。和&lt;。

要获取格式化的日期字符串,使其永远不会被错误解释,请使用以下格式转换为yyyy-mm-dd格式:

select convert(varchar(10), getdate(), 120)

另外,它甚至可以正确排序!有关转换及其格式参数的完整信息,请参见在线SQL服务器书籍:Books online