2010-10-01 14 views
6

Ho una domanda che va qualcosa come questo:selezionare il nome della colonna da Query max

;WITH t as 
(
select 1 as RowNumber, 1 as ObjectID, 10 as [Col1], 20 as [Col2], 20 as [Col3], 20 as [Col4] UNION ALL 
select 2 as RowNumber, 2 as ObjectID, 20 as [Col1], 30 as [Col2], 40 as [Col3], 50 as [Col4] 
) 
SELECT RowNumber, ObjectID, 
     (
     SELECT MAX(Amount) 
     FROM (
       SELECT [Col1] AS Amount 
       UNION ALL 
       SELECT [Col2] 
       UNION ALL 
       SELECT [Col3] 
       UNION ALL 
       SELECT [Col4] 
       ) d 
     WHERE Amount > 0 
     ) 
FROM t 

La query funziona bene, ma voglio sapere è dove il Max (Importo) proviene.

Quindi nel mio set di risultati, oltre a (RowNumber, ObjectId, Amount) voglio il nome della colonna (Col1, Col2, Col3, Col4) come stringa.

C'è un modo per farlo?

EDIT Domanda dai commenti: Se due colonne hanno lo stesso valore massimo, potrebbe essere o uno? Sì, potrebbe essere uno dei due. Qualsiasi nome di colonna farà finché saprò da dove potrebbe provenire.

Utilizzo di SQL Server 2008

+0

Cosa RDBMS stai usando? –

+1

Cosa succede se sia Col1 che Col2 hanno lo stesso MAX: potrebbe essere uno dei due ...? – gbn

+0

Spero non ti dispiaccia Ho appena modificato il tuo codice per renderlo un esempio percorribile come non avevo mai visto prima. Sentiti libero di tornare indietro! –

risposta

1

È possibile utilizzare una combinazione di UNPIVOT e OUTER APPLY:

;WITH t as  (
select 1 as RowNumber, 1 as ObjectID, 10 as [Col1], 20 as [Col2], 
     20 as [Col3], 20 as [Col4] UNION ALL 
select 2 as RowNumber, 2 as ObjectID, 20 as [Col1], 30 as [Col2], 
     40 as [Col3], 50 as [Col4]) 
SELECT 
    RowNumber, 
    ObjectID, 
    ColName, 
    ColAmount 
FROM t 
OUTER APPLY (
    SELECT TOP 1 
    ColName, 
    ColAmount 
    FROM 
    (
     SELECT 
     Col1, 
     Col2, 
     Col3, 
     Col4 
    ) x 
    UNPIVOT (
     ColAmount FOR ColName IN (Col1, Col2, Col3, Col4) 
    ) y 
    WHERE ColAmount > 0 
    ORDER BY ColAmount DESC 
) z 

Risultati:

RowNumber ObjectID ColName ColAmount 
----------- ----------- --------- ----------- 
1   1   Col2  20 
2   2   Col4  50 
+0

Grazie, questa si è rivelata la soluzione migliore qui. Non conoscevo la funzione UNPIVOT ma è esattamente quello che stavo cercando. –

5

Non MAX: utilizzare TOP che evita l'aggregato/GROUP BY.

Si può anche trattare con i duplicati utilizzando WITH TIES

Non sono sicuro se ciò che si aveva era pseudo-codice o un sub-query, ma questo dovrebbe fare quello che vuoi

SELECT TOP 1 -- WITH TIES if needed 
    * 
FROM 
    (
    SELECT RowNumber, ObjectID, [Col1] AS Amount, 'Col1' AS ColName 
    FROM table 
    UNION ALL 
    SELECT RowNumber, ObjectID, [Col2], 'Col2' AS ColName 
    FROM table 
    UNION ALL 
    SELECT RowNumber, ObjectID, [Col3], 'Col3' AS ColName 
    FROM table 
    UNION ALL 
    SELECT RowNumber, ObjectID, [Col4], 'Col4' AS ColName 
    FROM table 
    ) foo 
WHERE Amount > 0 
ORDER BY Amount DESC 

Il tuo problema principale è che dovrai toccare la tabella 4 volte, indipendentemente da come lo fai perché una sottoquery restituisce solo un valore. Non riesco a vedere neanche una soluzione ROW_NUMBER (ma probabilmente ce n'è una anche ... :-)

+0

La sua domanda lo stava facendo per riga. Non ho mai saputo che tu potessi farlo. –

+0

@Martin Smith: Funziona, ma non sono sicuro di come ottenere il columnname perché è una sottoquery che consente solo un valore. Vedere questi collegamenti: http://sqlblogcasts.com/blogs/simons/archive/2006/05/08/Neat-trick-to-find-max-value-of-multiple-columns.aspx o http: // sqlblogcasts. com/blogs/simons/archive/2006/05/16/Performance-of-MAX-trick.aspx – gbn

+0

Non l'ho mai visto prima. Grazie per i link! –

3

Questo non è stato verificato: tuttavia per vedere che cosa sta succedendo con i tuoi dati, questo potrebbe aiutare. Non proprio la qualità del codice di produzione:

SELECT RowNumber, ObjectID, 
     (
     SELECT MAX(Amount) 
     FROM (
       SELECT str([Col1]) + ", col1, " AS Amount 
       UNION ALL 
       SELECT str([Col2]) + ", col2" 
       UNION ALL 
       SELECT str([Col3]) + ", col3" 
       UNION ALL 
       SELECT str([Col4]) + ", col4" 
       ) 
     WHERE Amount > 0 
     ) 
FROM table 

str() è la funzione "toString()" del DBMS. Il tuo SQL sembra abbastanza strano, che DBMS stai usando?

+0

Dovresti avere "Importo>" 0 ", ma questo è abbastanza pulito + 1 – gbn

+0

Questo è un modo intelligente per farlo. Non ho pensato di aggiungere il nome della colonna come una stringa del genere. Grazie –

2

Aggiunta di un passo per user202553's answer

;WITH t1 as(
select 1 as RowNumber, 1 as ObjectID, 10 as [Col1], 20 as [Col2], 20 as [Col3], 20 as [Col4] UNION ALL 
select 2 as RowNumber, 2 as ObjectID, 20 as [Col1], 30 as [Col2], 40 as [Col3], 50000045 as [Col4] 
), 
t2 as(
SELECT RowNumber, ObjectID, 
     (
     SELECT TOP 1 CAST(C AS BINARY(4)) + CAST(Amount as BINARY(4)) 
     FROM (
       SELECT 'Col1' AS C, [Col1] AS Amount 
       UNION ALL 
       SELECT 'Col2' AS C, [Col2] 
       UNION ALL 
       SELECT 'Col3' AS C, [Col3] 
       UNION ALL 
       SELECT 'Col4' AS C, [Col4] 
       ) d 
     WHERE Amount > 0 
     ORDER BY Amount desc 
     ) AS Top1 
FROM t1 
) 
SELECT RowNumber, 
     ObjectID, 
     CAST(Left(Top1, 4) AS CHAR(4)) AS Col, 
     CAST(SUBSTRING(Top1,5,4) AS INT) AS Amount 
FROM t2 
+0

Grazie, anche questo è abbastanza pulito –

+0

Ancora più ordinato quindi stringa concat: lunghezza fissa "codifica" – gbn

Problemi correlati