2015-05-29 56 views
5

我有一个包含示例数据的表,如下所示。SQL - 获取具有最大值的列的索引

col1 col2 col3 
4  6  9 
7  1  5 

我想有值的最大数值匹配该行,如果他们是平等的,只是忽略了后列的索引。

举例来说,结果应该是返回

3 (because col3 has maximum value 9) 
1 (because col1 has maximum value 7) 

请注意,列数是不确定的,所以我需要一个通用的解决方案。

谢谢

+0

如果他们是平等的什么你要吗? –

+0

如果他们是平等的,只是忽略后者。 – YukiSakura

回答

4

的更通用的解决方案(即N列),这是为了将列转移到行中,然后可以应用窗口函数来获得每列“行”的组合最大值。然而,你将需要每行的某种关键字,以便可以以行方式应用最大值(以允许重新组合原始行)。我已经通过newId()添加代理Guid来完成此操作。注意:此方法返回列名,每行的最高值:

WITH MyTableWithRowId AS 
(
    SELECT newId() AS Id, * 
    FROM MyTable 
), 
Unpivoted AS 
(
    SELECT Ndx, Id, col, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY col DESC) AS Rnk 
    FROM 
    MyTableWithRowId tbl 
    UNPIVOT 
    (
     col for Ndx in(col1, col2, col3) 
    ) p 
) 
SELECT Ndx 
FROM Unpivoted 
WHERE Rnk = 1 

SqlFiddle here

编辑,重新只是 '1,2,3' 不是列名(COL1,COL2,COL3 )

按@的Giorgi的评论,如果你真的想每行中的列(一个基于)序号位置,你可以加入回DMV的如INFORMATION_SCHEMA.COLUMNS查找序,虽然这将是可怕的脆弱的战略IMO。

WITH MyTableWithRowId AS 
(
    SELECT newId() AS Id, col1, col2, col3 
    FROM MyTable 
), 
TheOrdinalPositionOfColumns AS 
(
    SELECT COLUMN_NAME, ORDINAL_POSITION 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = 'MyTable' 
), 
Unpivoted AS 
(
    SELECT Ndx, Id, col, ROW_NUMBER() OVER (PARTITION BY Id ORDER BY col DESC) AS Rnk 
    FROM 
    MyTableWithRowId tbl 
    UNPIVOT 
    (
     col for Ndx in(col1, col2, col3) 
    ) p 
) 
SELECT topoc.ORDINAL_POSITION AS ColumnOrdinalPosition 
FROM Unpivoted 
JOIN TheOrdinalPositionOfColumns topoc ON Unpivoted.Ndx = topoc.COLUMN_NAME 
WHERE Rnk = 1; 

Updated Fiddle with Giorgi's Column naming

+1

如果列名是'SomeCol OtherCol WhatCol',这将不起作用。 http://sqlfiddle.com/#!6/4b7bc/1 –

+0

你的答案看起来不错。不过,我只需要索引(1而不是col1)。你能修改你的答案吗? – YukiSakura

+0

@YukiSakura我有 - 第二个查询将返回列的序数。在创建表时,您需要防止对DDL进行更改,并防止对列结构进行DDL修改。 – StuartLC

3

尝试这样的事情

select 
case when col1 >= col2 and col1 >= col3 then 1 
    when col2 >= col1 and col2 >= col3 then 2 
    else 3 end as [index] 
from myquestion_table 

看到一个DEMO HERE

+1

我想,用OP的最新评论'如果他们是平等的,只要忽略后面'你应该改'''''= ='选择第一列。 –

+0

@GiorgiNakeuri,谢谢指出,顺便说一下OP何时评论过......没有看到。 – Rahul

+0

在他的问题。 –

4

你可以这样说:

select case 
      when col1 >= col2 and col1 >= col3 then 1 
      when col2 >= col1 and col2 >= col3 then 2 
      when col3 >= col1 and col3 >= col2 then 3 
     end as ColIndex 
from table 
+0

你不需要有第三个'时'而不是写'else' :) –

+1

是的,但这种方式所有的答案将是相同的:)我的是不同的! –

+0

我喜欢与众不同! ;)+1 –

2

试试这个:

select case 
    when col1 >= col2 and col1 >= col3 then 1 
    when col2 >= col1 and col2 >= col3 then 2 
    else 3 
    end as ind 
from mytable 
2

这是一个非常基本的例子,但它是这样的:

select case when col1 > col2 and col1 > col3 then col1 
     when col2> col3 then col2 
     else col3 end as greatestColumn 
    from table 
2

试试这一个,没有支点。

- 您可以添加N个列。

CREATE TABLE Table1 
    ([id] int primary key identity(1,1),[col1] int, [col2] int, [col3] int) 
; 

INSERT INTO Table1 
    ([col1], [col2], [col3]) 
VALUES 
    (4, 6, 9), 
    (7, 1, 5) 
; 

DECLARE @tempTable as table(name varchar(50),maxValue int) 


DECLARE @maxColumn int 
SELECT @maxColumn = max(ordinal_position) 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = N'Table1' 

DECLARE @maxRow int 
SELECT @maxRow = Count(col1) FROM Table1 


DECLARE @rowCounter int = 1 
DECLARE @colCounter int = 1 

DECLARE @columnName varchar(max) 
DECLARE @colValue varchar(max) 
DECLARE @q nvarchar(max) 


DECLARE @maxValue int 
DECLARE @ParmDefinition nvarchar(500) 
DECLARE @FinalResult table (id int, columnName nvarchar(max)) 
DECLARE @rowId int 

WHILE(@rowCounter <= @maxRow) 
BEGIN 
    WHILE (@colCounter <= @maxColumn) 
    BEGIN 

     SELECT @columnName = COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS 
     WHERE TABLE_NAME = N'Table1' and ordinal_position = @colCounter 

     --select @columnName,@rowCounter,@colCounter 

     SELECT @q = 'select @retvalOUT =' + @columnName + ' from Table1 where id = ' + cast(@rowCounter as NVARCHAR) 

     SET @ParmDefinition = N'@retvalOUT int OUTPUT'; 

     EXEC sp_executesql @q,@ParmDefinition ,@retvalOUT = @maxValue OUT 
     --select '@maxValue' + @maxValue 

     INSERT INTO @tempTable VALUES (@columnName,@maxValue) 

     SET @colCounter = @colCounter + 1 
    END 



SELECT @rowId = maxValue FROM @tempTable WHERE name LIKE 'id' -- Primary key column 

INSERT INTO @FinalResult(id,columnName) 
SELECT TOP 1 @id,name FROM @tempTable WHERE name not like 'id' ORDER BY maxvalue DESC 

DELETE FROM @tempTable 

--select * from @FinalResult 

SET @colCounter = 1 
SET @rowCounter = @rowCounter + 1 
END 

SELECT * FROM @FinalResult 
2

这里是另一个支点的解决方案,它比其他支点的解决方案更短一点:

DECLARE @t table 
(col1 int, col2 int, col3 int) 
INSERT @t 
SELECT 4,8,9 union all SELECT 7,1,5 

;WITH addrownumber AS 
(
    SELECT 
    rn = row_number() over (order by (select 1)), 
    * 
    FROM @t 
) 
, unpiv AS 
(
    SELECT 
    rn, 
    value, 
    colname, 
    ordinalposition = row_number() over (partition by rn order by (select 1)), 
    rn2 = row_number() over (partition by rn order by value DESC, rn) 
    FROM addrownumber as p 
    UNPIVOT 
    (value FOR colname IN   
    ([col1], [col2], [col3])) AS unpvt 
    -- since you need all columns to be mentioned in pivot, you can set up 
    -- the ordinal order here, by putting in columns in the right order. 
) 
SELECT ordinalposition, value, colname 
FROM unpiv 
WHERE rn2 = 1 

结果:

ordinalposition value colname 
3    9  col3 
1    7  col1 
相关问题