奇怪的T-SQL DATEADD溢出

时间:2017-06-22 18:03:56

标签: tsql

我试图将数字(16,8)添加到smalldatetime。我收到一个我无法理解的溢出错误。

metric_value是数字,business_date是smalldatetime。

SELECT
    rsda.name
    , business_date
    , metric_value
    , DATEADD(dd, metric_value, business_date) AS o_dt
    , metric.name
FROM [redacted] met
INNER JOIN [redacted] rsda ON met.bu_id = rsda.data_accessor_id
INNER JOIN Metric ON met.metric_id = metric.metric_id
WHERE CHARINDEX('Remodel', metric.name) > 0

Msg 517, Level 16, State 2, Line 1
Adding a value to a 'smalldatetime' column caused an overflow.

我意识到明显的答案是"你的一个日期超过了9999年和#34;但这不是这种情况。所有日期都在2017年,并且所有数字都是100以下的整数,至少在WHERE子句为真时。

会议桌上有很多其他不相关的数据给我的改造'标准,我想知道这是否会导致错误。这是一张奇怪的桌子,但我无法控制它的设计。是否有可能在应用我的WHERE子句之前发生了部分DATEADD进程?我无法想象还有什么。

修改即可。当我删除DATEADD字段时:

这是' ORDER BY business_date ASC'

的第一行
+----------+---------------------+--------------+-------------+
|   name   |    business_date    | metric_value |    name     |
+----------+---------------------+--------------+-------------+
| 466 - 94 | 2017-03-13 00:00:00 | 59.00000000  | FullRemodel |
+----------+---------------------+--------------+-------------+

ORDER BY business_date DESC

+----------+---------------------+-------------+-------------+
| 440 - 87 | 2017-07-31 00:00:00 | 38.00000000 | FullRemodel |
+----------+---------------------+-------------+-------------+

ORDER BY metric_value ASC

+----------+---------------------+------------+----------------+
| 471 - 05 | 2017-05-01 00:00:00 | 0.00000000 | PartialRemodel |
+----------+---------------------+------------+----------------+

ORDER BY metric_value DESC

+----------+---------------------+-------------+-------------+
| 466 - 86 | 2017-03-13 00:00:00 | 59.00000000 | FullRemodel |
+----------+---------------------+-------------+-------------+

3 个答案:

答案 0 :(得分:0)

  

是否有可能在应用我的WHERE子句之前发生了部分DATEADD进程?

是。计算表达式的计算标量可以在行被过滤之前在行上运行。有关此主题的一些链接位于my answer here

如果两个输入将导致smalldatetime范围的有效日期,则可以使用CASE表达式仅执行dateadd。

CASE 
 WHEN metric_value BETWEEN datediff(day, business_date, '1900-01-01') 
                       AND datediff(day, business_date, '2079-06-06')
 THEN 
  DATEADD(day, metric_value, business_date) 
END

答案 1 :(得分:0)

或者您也可以使用(在SELECT中)

CASE 
  WHEN metric_value <= datediff(day, GETDATE(), '20790606') 
  THEN DATEADD(day, metric_value, business_date) 
  ELSE NULL 
END AS o_dt

在日期时间使用BETWEEN会变得很小,所以我尽量避免使用它。

编辑:根据马丁的评论,我不再认为这是一个有效的解决方案。

  

结合@Martin Smith的回答,你也可以改变你的想法   查询子查询,它应该过滤掉那些行   导致错误。

SELECT t1.rsda_name
    , t1.business_date
    , t1.metric_value
    , DATEADD(day, t1.metric_value, t1.business_date) AS o_dt
    , t1.metric_name
FROM (
    SELECT
        rsda.name AS rsda_name
        , business_date
        , metric_value
        , metric.name AS metric_name
    FROM [redacted] met
    INNER JOIN [redacted] rsda ON met.bu_id = rsda.data_accessor_id
    INNER JOIN Metric ON met.metric_id = metric.metric_id
    WHERE CHARINDEX('Remodel', metric.name) > 0
) t1

答案 2 :(得分:-1)

你需要在DATEADD()函数中用DAY替换'dd'。