2015-05-29 81 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 
相關問題