2010-10-01 18 views
6

Tengo una consulta que es algo como esto:seleccionar el nombre de la columna de consulta máximo

;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 consulta funciona bien, pero yo quiero saber es donde el Max (Cantidad) viene.

Así que en mi conjunto de resultados, además de tener (RowNumber, ObjectId, Amount) quiero el nombre de la columna (Col1, Col2, Col3, Col4) como una cadena.

¿Hay alguna manera de hacerlo?

EDIT Pregunta de los comentarios: si dos columnas tienen el mismo valor máximo, ¿podría ser una? Sí, podría ser cualquiera. Cualquier nombre de columna servirá mientras sepa de dónde podría provenir.

Uso de SQL Server 2008

+0

Lo RDBMS está usando? –

+1

¿Qué pasa si tanto Col1 como Col2 tienen el mismo MAX: podría ser uno ...? – gbn

+0

Espero que no te importe. Acabo de editar tu código para que sea un ejemplo ejecutable, ya que nunca antes había visto ese enfoque. ¡Siéntase libre de deshacerlo! –

Respuesta

1

Usted puede utilizar una combinación de UNPIVOT y 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 

Resultados:

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

Gracias, esta resultó ser la mejor solución aquí. No sabía acerca de la función UNPIVOT, pero es exactamente lo que estaba buscando. –

5

No MAX: utilizar la parte superior que evita el agregado/GROUP BY.

También puede hacer frente a los duplicados utilizando CON LAZOS

No estoy seguro de si lo que tenía era pseudo-código o una sub-consulta, pero esto debe hacer lo que quiera

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 

Su problema principal es que deberá tocar la tabla 4 veces sin importar cómo lo haga, porque una subconsulta solo devuelve un valor. No puedo ver una solución ROW_NUMBER tampoco (pero probablemente hay una aunque ... :-)

+0

Su consulta lo hacía por fila. Nunca supe que pudieras hacer eso. –

+0

@Martin Smith: funciona, pero no estoy seguro de cómo obtener también el nombre de columna porque es una subconsulta que permite un solo valor. Vea estos enlaces: 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

Sí, nunca antes había visto eso. Gracias por los enlaces! –

3

Esto no se ha probado: sin embargo, para ver qué está pasando con sus datos, esto podría ayudar. No es realmente la calidad del código de producción:

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() es la función "toString()" de su DBMS. Su SQL parece bastante extraño, ¿qué DBMS está utilizando?

+0

Tendría que tener 'Cantidad '' 0'', pero esto es bastante limpio + 1 – gbn

+0

Esa es una forma inteligente de hacerlo. No pensé en agregar el nombre de la columna como una cadena así. Gracias –

2

Adición de un paso a 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

Gracias, eso también es bastante limpio –

+0

Aún más ordenado que concat: longitud de longitud "codificación" – gbn

Cuestiones relacionadas