如何选择具有最大值列的行与group by

时间:2017-11-13 10:24:26

标签: sql oracle oracle12c

我有一个包含下一列的表

MSG_ID          NOT NULL NUMBER(10)     
CREATION_DATE            DATE           
PORT                     VARCHAR2(50)   
MESSAGE                  VARCHAR2(1024) 
IP_ADDRESS               VARCHAR2(50)   
PARSED                   NUMBER(1)      
PARSED_ON                DATE    

解析时间为parsed_on - creation_date。

我想知道是否有可能在1个单一查询中提取每小时需要更长时间解析的消息,获得HOUR,PORT,MSG_ID MINUTES ......我在这里被阻止

select TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR, PORT, MSG_ID, ROUND(MAX(parsed_on -  creation_date)) * 24*60 MINUTES
        from T_INCOME_CALLS 
         where TO_CHAR(CREATION_DATE, 'dd/mm/yyyy') = TO_CHAR(SYSDATE, 'dd/mm/yyyy') 
        group by TO_CHAR(CREATION_DATE, 'HH24'), PORT, MSG_ID
         order by TO_CHAR(CREATION_DATE, 'HH24') ;

3 个答案:

答案 0 :(得分:1)

您可以使用窗口函数row_number来查找每小时分析时间最长的行,如下所示:

select *
from (
    select to_number(to_char(creation_date, 'HH24')) as hour,
        port,
        msg_id,
        round(parsed_on - creation_date) * 24 * 60 as parse_time,
        row_number() over (
            partition by to_char(creation_date, 'HH24'), port, msg_id
            order by (parsed_on - creation_date) desc nulls last
            ) as rn
    from t_income_calls t
    where creation_date between trunc(sysdate) 
                            and trunc(sysdate + 1) - interval '1' second
    ) t
where rn = 1;

另外,请注意过滤器。我在creation_date上使用了日期范围而不是to_char。在creation_date上使用to_char会禁止在creation_date上使用索引(如果存在)。

答案 1 :(得分:1)

我认为需要的是每小时花费大部分时间的项目,用于IP_ADDRESS和PORT的分组,这与您的原始查询不同。我也假设MSG_ID是唯一的。

如果您希望每个记录小时只有1行,那么请使用row_number(),如果您想要绑定值,请在下面的查询中替换dense_rank()。 create_on日期已被用作排序烧杯。

SELECT
       TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR
     , PORT, MSG_ID
     , ROUND(parsed_on -  creation_date) * 24*60 MINUTES
FROM (
      SELECT
            T_INCOME_CALLS.*
           , ROW_NUMBER() OVER(PARTITION BY IP_ADDRESS, port, TO_CHAR(CREATION_DATE, 'HH24') 
                                ORDER BY (parsed_on - creation_date) desc, CREATION_DATE) AS rn
      FROM T_INCOME_CALLS
      WHERE CREATION_DATE >= TRUNC(SYSDATE) AND CREATION_DATE < TRUNC(SYSDATE) + 1
      ) 
WHERE rn = 1

请避免将日期转换为where子句的字符串,这样效率不高。而是保持created_on不变,并修改标准以适应允许访问过滤索引的数据。

答案 2 :(得分:1)

使用FIRST函数时,您也可以在没有子查询的情况下获取它:

SELECT TO_CHAR(CREATION_DATE, 'HH24') || ':mm' HOUR, PORT, MSG_ID, 
    MAX(MESSAGE) KEEP (DENSE_RANK FIRST ORDER BY (parsed_on - creation_date) desc, CREATION_DATE)                
FROM T_INCOME_CALLS 
WHERE CREATION_DATE >= TRUNC(SYSDATE) AND CREATION_DATE < TRUNC(SYSDATE) + 1
GROUP BY TO_CHAR(CREATION_DATE, 'HH24'), PORT, MSG_ID
ORDER BY TO_CHAR(CREATION_DATE, 'HH24');