好的,首先我见过this thread。但是没有一个解决方案非常令人满意。提名的答案看起来像NULL会打破它,而评分最高的答案看起来很难维持。 所以我想知道以下内容:
CREATE FUNCTION GetMaxDates
(
@dte1 datetime,
@dte2 datetime,
@dte3 datetime,
@dte4 datetime,
@dte5 datetime
)
RETURNS datetime
AS
BEGIN
RETURN (SELECT Max(TheDate)
FROM
(
SELECT @dte1 AS TheDate
UNION ALL
SELECT @dte2 AS TheDate
UNION ALL
SELECT @dte3 AS TheDate
UNION ALL
SELECT @dte4 AS TheDate
UNION ALL
SELECT @dte5 AS TheDate) AS Dates
)
END
GO
我看到的主要问题是,如果只有3个字段需要比较,你仍然需要为其他2个字段指定NULL,如果你想将它扩展到6个比较,它将破坏现有的使用。如果它是参数化存储过程,则可以为每个参数指定默认值,并且添加新参数不会破坏现有引用。同样的方法显然也可以扩展到其他数据类型或Min或Avg之类的东西。我有没有发现一些主要的缺点?请注意,无论传递给它的一些,全部或没有值是空值还是重复值,此函数都有效。
答案 0 :(得分:2)
您可以使用ISNULL函数解决null问题:
SELECT ISNULL(@dte1,0) AS TheDate
UNION ALL
SELECT ISNULL(@dte2,0) AS TheDate
UNION ALL
SELECT ISNULL(@dte3,0) AS TheDate
UNION ALL
SELECT ISNULL(@dte4,0) AS TheDate
UNION ALL
SELECT ISNULL(@dte5,0) AS TheDate) AS Dates
但它只适用于MAX函数。
以下是另一个建议:http://www.sommarskog.se/arrays-in-sql-2005.html
他们以字符串形式建议用逗号分隔值。
该功能需要尽可能多的参数,如下所示:
CREATE FUNCTION GetMaxDate
(
@p_dates VARCHAR(MAX)
)
RETURNS DATETIME
AS
BEGIN
DECLARE @pos INT, @nextpos INT, @date_tmp DATETIME, @max_date DATETIME, @valuelen INT
SELECT @pos = 0, @nextpos = 1
SELECT @max_date = CONVERT(DATETIME,0)
WHILE @nextpos > 0
BEGIN
SELECT @nextpos = charindex(',', @p_dates, @pos + 1)
SELECT @valuelen = CASE WHEN @nextpos > 0
THEN @nextpos
ELSE len(@p_dates) + 1
END - @pos - 1
SELECT @date_tmp = CONVERT(DATETIME, substring(@p_dates, @pos + 1, @valuelen))
IF @date_tmp > @max_date
SET @max_date = @date_tmp
SELECT @pos = @nextpos
END
RETURN @max_date
END
并致电:
DECLARE @dt1 DATETIME
DECLARE @dt2 DATETIME
DECLARE @dt3 DATETIME
DECLARE @dt_string VARCHAR(MAX)
SET @dt1 = DATEADD(HOUR,3,GETDATE())
SET @dt2 = DATEADD(HOUR,-3,GETDATE())
SET @dt3 = DATEADD(HOUR,5,GETDATE())
SET @dt_string = CONVERT(VARCHAR(50),@dt1,21)+','+CONVERT(VARCHAR(50),@dt2,21)+','+CONVERT(VARCHAR(50),@dt3,21)
SELECT dbo.GetMaxDate(@dt_string)
答案 1 :(得分:1)
为什么不呢:
SELECT Max(TheDate)
FROM
(
SELECT @dte1 AS TheDate WHERE @dte1 IS NOT NULL
UNION ALL
SELECT @dte2 AS TheDate WHERE @dte2 IS NOT NULL
UNION ALL
SELECT @dte3 AS TheDate WHERE @dte3 IS NOT NULL
UNION ALL
SELECT @dte4 AS TheDate WHERE @dte4 IS NOT NULL
UNION ALL
SELECT @dte5 AS TheDate WHERE @dte5 IS NOT NULL) AS Dates
这应该在不引入任何新值的情况下处理null问题
答案 2 :(得分:0)
更好的选择是重组数据以支持基于列的min / max / avg,因为这是SQL最擅长的。
在SQL Server 2005中,您可以使用UNPIVOT运算符执行转换。
并不总是适用于所有问题,但如果您可以使用它,可以使事情变得更容易。
请参阅:
http://msdn.microsoft.com/en-us/library/ms177410.aspx
http://blogs.msdn.com/craigfr/archive/2007/07/17/the-unpivot-operator.aspx
答案 3 :(得分:0)
我会在XML中传递日期(您可以使用varchar / etc,并转换为xml数据类型):
DECLARE @output DateTime
DECLARE @test XML
SET @test = '<VALUES><VALUE>1</VALUE><VALUE>2</VALUE></VALUES>'
DECLARE @docHandle int
EXEC sp_xml_preparedocument @docHandle OUTPUT, @doc
SET @output = SELECT MAX(TheDate)
FROM (SELECT t.value('./VALUE[1]','DateTime') AS 'TheDate'
FROM OPENXML(@docHandle, '//VALUES', 1) t)
EXEC sp_xml_removedocument @docHandle
RETURN @output
这将解决处理尽可能多的可能性的问题,我不会在xml中添加空值。
我会使用单独的参数来指定日期类型,而不是自定义xml&amp;每次支持代码,但您可能需要使用动态SQL才能工作。
答案 4 :(得分:0)
如果你只需要在一行上进行,那么你将如何做到这一点并不重要(一切都足够快)。
为了选择PER ROW的几列的Min / Max / Avg值,使用UNPIVOT的解决方案应该比UDF快得多
答案 5 :(得分:0)
另一种可能性是创建自定义表类型,如下所示:
CREATE TYPE [Maps].[TblListInt] AS TABLE( [ID] [INT] NOT NULL )
然后,
CREATE FUNCTION dbo.GetMax(@ids maps.TblListInt READONLY) RETURNS INT
BEGIN
RETURN (select max(id) from @ids)
END
当然,您可以将“int”与所需类型交换。