2015-02-10 16 views
0

背景:我需要在SQL Server 2008 10.0.5869的T-SQL中编写函数。如何在SQL中比较列并仅返回其中的一列

这里是我的工作表(为简单起见 - 我只放3列在这里 - 但我有10列的实际工作):

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

ID为varchar和列(x)都是日期时间。

我的最终目标是设计一个功能fn_CompareDate做这样的事情:

select fn_CompareDate(ID) from table where ID = 1 

上述查询应返回从塔(X)S的应该是2015-02最新的日期。

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

+0

你能改变你的模式吗? – Blorgbeard 2015-02-10 00:53:57

+0

可能的重复[什么是从多列中选择最小值的最佳方法?](http://stackoverflow.com/questions/368351/whats-the-best-way-to-select-the-minimum-value-从多个列) – Blorgbeard 2015-02-10 00:55:18

+0

看看http://stackoverflow.com/questions/1972051/sql-server-equivalent-to-oracle-至少唯一的区别 - 你需要最大 – 2015-02-10 00:55:26

回答

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 

希望你明白了。

+0

这与最小的LoC完美结合 - 谢谢。 – jiaoziren 2015-02-11 00:46:49

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; 
+0

我在这里学到了新东西,谢谢! – 2015-02-10 01:05:57

+0

这是我的建议根据您的建议,但它给了我一个语法错误(关键字'值'附近的语法不正确) - 请问如果这看起来没问题,请指教:选择d。从项目t交叉的maxd应用 (从列(1),(列2),(列3))中选择max(d)作为最大值,作为val(d))d 其中t.patid ='1' – jiaoziren 2015-02-10 01:33:06

+0

我已经只是注意到,val()不被识别为我的服务器上的函数(SQL Server 2008 10.0.5869) - 事实证明它不是R2 - 对不起我的坏。 – jiaoziren 2015-02-10 01:36:00

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 

希望这会有所帮助。

0

我发现从this question工程2号解决方案非常适合我:

创建一个类似的功能:

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 
    ) 
相关问题