如何比较列并在SQL中只返回其中一个

时间:2015-02-10 00:49:19

标签: sql sql-server tsql

背景:我需要在SQL Server 2008 10.0.5869上的T-SQL中编写一个函数。

这是我正在处理的表格(为了简单起见 - 我这里只列出3列 - 但我有10列用于实际工作):

ID | Column1 | Column2 | Column3
1  | 2014-05 | 2015-02 | 2013-04
2  | 2012-09 | 2011-02 | 2013-03

ID是varchar,Column(x)都是日期时间。

我的最终目标是设计一个函数fn_CompareDate来执行以下操作:

select fn_CompareDate(ID) from table where ID = 1

上面的查询应返回列(x)的最新日期,该日期应为2015-02。

我使用了CASE WHEN,但几乎不可能将它用于10列。还有另一种方法可以达到相同的效果吗?

4 个答案:

答案 0 :(得分:4)

一种方法是使用apply

select d.maxd
from table t cross apply
     (select max(d) as maxd
      from values ((id, column1), (id, column2), (id, column3)) as val(id, d)
      where val.id = t.id
     ) d
where t.id = 1;

编辑:

您可以在不values()的情况下执行此操作:

select d.maxd
from table t cross apply
     (select max(d) as maxd
      from (select id, column1 as d union all
            select id, column2 union all
            select id, column3 union all
            select id, column4
           ) val
      where t.id = val.id
     ) d
where t.id = 1;

答案 1 :(得分:2)

我认为以下功能可以更好地满足要求

CREATE FUNCTION fn_CompareDate(@ID VARCHAR(10))
RETURNS DATETIME
AS 
BEGIN   
    DECLARE @maxDate DATETIME;
    SELECT @maxDate =
    (SELECT Max(v) 
    FROM (VALUES (COLUMN1), (COLUMN2), (COLUMN3)) AS value(v)) 
    FROM table 
    WHERE ID = @ID

    RETURN @maxDate;
END;

现在运行以下查询

select dbo.fn_CompareDate(ID) from table where ID = 1

希望你明白了。

答案 2 :(得分:1)

您可以使用动态sql和INFORMATION_SCHEMA.COLUMNS。它应该在SQL Server 2008中工作。试试这个:

CREATE PROCEDURE sp_CompareDate
    @ID int,
    @tableName NVARCHAR(MAX) = 'table2', -- Your table name
    @dbName NVARCHAR(MAX) = 'temp'       -- Your database name
AS
BEGIN
    DECLARE @maxFieldValue DATETIME
    DECLARE @curFieldName NVARCHAR(MAX)
    DECLARE @curFieldValue DATETIME
    DECLARE @sql NVARCHAR(MAX)
    DECLARE fieldCursor CURSOR  FOR 
            SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_NAME = @tableName 
            AND TABLE_CATALOG = @dbName AND COLUMN_NAME != 'ID'
    OPEN fieldCursor

    FETCH NEXT FROM fieldCursor INTO @curFieldName
    SET @sql = N'USE [' + @dbName + N'] SELECT @curDate=' + @curFieldName 
        + N' FROM ' + @tableName + N' WHERE ID=' + CAST(@ID AS NVARCHAR) 
    EXEC sp_executesql @sql, N'@curDate DATETIME output', @curFieldValue output;
    SET @maxFieldValue = @curFieldValue

    WHILE (@@FETCH_STATUS = 0)
    BEGIN
        SET @sql = N'USE [' + @dbName + N'] SELECT @curDate=' + @curFieldName 
            + N' FROM ' + @tableName + N' WHERE ID=' + CAST(@ID AS NVARCHAR)
        EXEC sp_executesql @sql, N'@curDate DATETIME output', @curFieldValue output;
        FETCH NEXT FROM fieldCursor INTO @curFieldName

        IF (@maxFieldValue < @curFieldValue) SET @maxFieldValue = @curFieldValue        
    END
    CLOSE fieldCursor;
    DEALLOCATE fieldCursor;
    SELECT @maxFieldValue
END

希望这有帮助。

答案 3 :(得分:0)

我发现this question的第二个解决方案对我来说效果很好:

创建一个类似于此的函数:

select max(col) from 
    (
        select column1 [col] from table where id = @id
        union all
        select column2 from table where id = @id
        union all
        select column3 from table where id = @id
    )