2008-10-22 17 views
5

Estoy intentando escribir una consulta para SQL Server 2005 pero no puedo encontrar la manera de hacerlo. Tengo una tabla con los siguientes campos:Semi-Tricky SQL Query

de identificador de mensaje int
CategoryID int
Prioridad tinyint
MessageText NVARCHAR (MAX)

necesito una consulta que devolverá * para cada fila que tiene la más alta prioridad dentro de una Categoría. Por ejemplo, si tuviera los siguientes datos:

MessageID, CategoryID, Prioridad, MessageText
1, 100, 1, Error # 1234 se produjo
2, 100, 2, Error # 243 ocurrió
3 , 100, 3, Error # 976 ocurrieron
4, 200, 4, Error # 194 ocurrieron
5, 200, 1, Error # 736 ocurrieron
6, 300, 3, Error # 54 ocurrieron
7, 300 , 2, se produjo el error # 888

entonces el resultado sería:

MessageID, CategoryID, Prioridad, MessageText
3, 100, 3, Error # 976 ocurrió
4, 200, 4, Error # 194 ocurrieron
6, 300, 3, se produjo el error n. ° 54

Observe que devuelve una fila por categoría, y que es la fila que tenía la prioridad más alta para esa categoría.

¿Alguien me puede decir cómo puedo escribir esta consulta?

+0

Se podría escribir mucho más fácil el uso de funciones analíticas en Oracle. :) – TheSoftwareJedi

+0

O utilizando las funciones analíticas en SQL Server y no tener que realizar un puerto a Oracle. – cfeduke

Respuesta

6

verificado:

SELECT 
    highest_priority_messages.* 
FROM 
(
    SELECT 
    m.MessageID 
    , m.CategoryID 
    , m.Priority 
    , m.MessageText 
    , Rank() OVER 
     (PARTITION BY m.CategoryID ORDER BY m.Priority DESC) AS p_rank 
    FROM [Message] m 
    GROUP BY 
     m.CategoryID 
     , m.Priority 
     , m.MessageID 
     , m.MessageText 
) highest_priority_messages 
WHERE 
    p_rank = 1 
+0

También querrá agregar un CreatedDate y calcular eso en la ecuación para ordenar, estoy seguro. – cfeduke

+0

¿Estás seguro de que no hay forma de usar PARTITION aquí sin usar Rank()? – skb

+0

Podría hacer MAX (m.Priority) OVER (PARTICIÓN POR m.CategoryID) AS MaxPriority, pero luego WHERE tendría que comparar la Prioridad a MaxPriority. También depende de si desea múltiplos de la máxima prioridad o no. –

1

creo que esto debería funcionar, nombre de la tabla asumido como mensajes

SELECT 
    M.MessageId, 
    M.CategoryId, 
    M.Priority, 
    M.MessageText 
FROM 
(
    SELECT 
     CategoryId, 
     MAX(Priority) AS Priority 
    FROM Messages 
    GROUP BY CategoryId 
) AS MaxValues 
    INNER JOIN Messages M 
     ON (MaxValues.CategoryId = M.CategoryId 
       AND MaxValues.Priority = M.Priority) 

NOTA

La única "Gotcha" en este método es que si usted tiene más de una prioridad máx ..

0
SELECT 
    Messages.MessageID 
    , Messages.CategoryID 
    , Messages.Priority 
    , Messages. MessageText 
FROM 
    Messages 
    INNER JOIN 
    (
     SELECT 
      CategoryID 
      , MAX(Priority) AS Priority 
     FROM 
      Messages 
     GROUP BY 
      CategoryID 
    ) AS MaxResults 
    ON 
     (
      Messages.CategoryID = MaxResults.CategoryID 
      AND 
      Messages.Priority = MaxResults.Priority 
     ) 

Parece que esta es básicamente la misma respuesta dada anteriormente ... con la misma advertencia.

Aunque esta funcionará de inmediato.

+0

Wow, no noté que mi alias fue quitada ... –

0

Esto es más corto y más fácil de leer (OMI).

select ms.* 
from 
    messages ms 
,(
    select ms1.categoryid, max(ms1.priority) as max_priority 
    from messages ms1 
    group by ms1.categoryid 
) tmp 
where ms.categoryid = tmp.categoryid 
    and ms.priority = tmp.max_priority; 
1

Si desea hacerlo sin la totalidad de las subconsultas:

SELECT 
    MessageID, 
    CategoryID, 
    Priority, 
    MessageText 
FROM 
    dbo.Messages M1 
LEFT OUTER JOIN dbo.Messages M2 ON 
    M2.CategoryID = M1.CategoryID AND 
    M2.Priority > M1.Priority 
WHERE 
    M2.MessageID IS NULL 

Es posible que tenga que ajustar la consulta en función de cómo desea gestionar las relaciones. No tenías ninguno de esos ejemplos, así que no estaba seguro.

0

No estoy muy alto rango suficiente (aún) para publicar un comentario, así que me gustaría añadir a la solución de cfeduke:

SELECT 
    highest_priority_messages.* 
FROM 
(
    SELECT 
    m.MessageID 
    , m.CategoryID 
    , m.Priority 
    , m.MessageText 
    , Rank() OVER 
     (PARTITION BY m.CategoryID ORDER BY m.Priority DESC, m.MessageID DESC) AS p_rank 
    FROM [Message] m 
    GROUP BY 
     m.CategoryID 
     , m.Priority 
     , m.MessageID 
     , m.MessageText 
) highest_priority_messages 
WHERE 
    p_rank = 1 

Si agrega otra CategoryID 100 Mensaje con prioridad 3, el La solución original devolvería 2 filas, al agregar otra condición de orden eliminamos la posibilidad de que dos elementos obtengan el mismo puntaje.

Aquí hay una copia de la fila que inserté para probar esto.

insert into [Message] (MessageID, CategoryID, Priority, MessageText) 
select 8, 100, 3, 'Error #976-2 occurred' 
1
select distinct query1.* from 

(select categoryId,msgText,max(priorityId) as MAX_PRIORITY 
from message 
    group by categoryId,msgText 
order by categoryId 
) query1, 


(select categoryId,max(priorityId) as MAX_PRIORITY 
from message 
    group by categoryId 
order by categoryId 
) query2 

where query1.MAX_PRIORITY = query2.MAX_PRIORITY 

order by query1.categoryId 
0
SELECT DISTINCT CategoryId,PS.Priority,MessageID,MessageText 
FROM Priority_Scene PS 
JOIN (SELECT MAX(Priority) AS Priority FROM Priority_Scene GROUP BY CategoryId) A 
ON A.Priority = PS.Priority 
+1

Si la misma categoría tiene dos prioridades en el mismo nivel y la más alta, entonces también funcionará – Kamy