3

在 SQL Server 中,我需要DATEADD用另一个函数包装内置函数。

问题是我需要实现这种行为:

返回类型

返回数据类型是日期参数的数据类型[...]

例如,如果我传入 adatetime作为参数,则DATEADD返回 a datetime。如果我传入 a date,则DATEADD返回 a date

以下示例始终返回datetime...

create function add_months(@dt date, @interval int) 
   returns datetime
as
begin
   return DATEADD(month, @interval, @dt)
end

如何在 SQL Server 中实现这一点?

(编辑)

语境

我正在执行从 informix 到 SQL Server 的数据库迁移。数据库部分不是这里的问题,代码才是。我们有数百个程序必须更改,因为其中嵌入了 SQL 查询。这是我试图避免使用的主要原因DATEADD(MONTH, 1, foo)。这种自动转换虽然在大多数情况下很简单,但在某些情况下可能非常困难。使用 udf,我可以只替换 informix 函数的名称,而无需进行更深入的重构。

4

2 回答 2

3

重载函数是不可能的。我正试图想办法硬塞SQL_VARIANT进去,但我能想到的所有选择都会导致不必要的恶心并发症。我会创建一个接受和返回日期的函数,以及一个接受和返回日期时间的函数,然后调用适当的函数。精度较低的可以调用精度较高的,因此您不必复制代码,例如

CREATE FUNCTION dbo.add_months_to_datetime
(@dt DATETIME, @interval INT)
RETURNS DATETIME
AS
BEGIN
  RETURN DATEADD(MONTH, @interval, @dt);
END
GO

CREATE FUNCTION dbo.add_months_to_date
(@dt DATE, @interval INT)
RETURNS DATE
AS
BEGIN
  RETURN dbo.add_months_to_datetime(@dt, @interval);
END
GO

或者,始终使用最高精度(第一个函数),并在呈现数据时担心它是日期还是日期时间。您可以使用内联转换或将其适当地包装在另一个函数中来执行此操作。

编辑

或者更好的是,只需用适当的内联 dateadd 调用替换对这个有问题的函数的所有调用。

dbo.add_months(foo, 1)

变成:

DATEADD(MONTH, 1, foo)

虽然它不像您希望的那样自动,但除了保持输出类型与输入相同的要求外,这还可能会提高某些查询的性能,具体取决于查询中使用这些查询的位置。

于 2012-07-05T17:09:49.283 回答
2

由于 SQL Server 中标量函数的性能不佳,我通常会避免这种情况或使用 Aaron 的技术。

但是,如果您必须使用该语法,则可以使用这样的可憎:

create function dbo.add_months(@dt sql_variant, @interval int) 
   returns sql_variant
as
begin
   IF SQL_VARIANT_PROPERTY(@dt, 'BaseType') = 'datetime'
       return DATEADD(month, @interval, CAST(@dt AS DATETIME))
   ELSE IF SQL_VARIANT_PROPERTY(@dt, 'BaseType') = 'date'
       return DATEADD(month, @interval, CAST(@dt AS DATE))
   RETURN null
end

DECLARE @d DATE = '20120705';
DECLARE @dt DATETIME = '20120705 12:30:30';

SELECT dbo.add_months(@d, 1), dbo.add_months(@dt, 1);

您可以在此 SQLFiddle 中看到,现在将数据从 sql_variant 提取到有用的东西中存在问题:http ://sqlfiddle.com/#!6/f95ba/4

于 2012-07-05T17:16:34.993 回答