Group By不在Oracle工作

时间:2010-12-08 17:18:27

标签: sql oracle join

我有两个表 - CALL和ACTIONS_HISTORY - 其中ACTIONS_HISTORY包含与每个CALL相关的操作。每次通话都不会有任何动作。

我想为每次通话选择最近的操作。这是我当前的SQL:

    SELECT CALL.CALL_ID,
           ACTIONS_HISTORY_ID
      FROM ACTIONS_HISTORY
RIGHT JOIN CALL ON ACTIONS_HISTORY.CALL_ID = CALL.CALL_ID
  GROUP BY CALL.CALL_ID, ACTIONS_HISTORY_ID

此SQL也返回相同的结果:

    SELECT DISTINCT
           CALL.CALL_ID,
           ACTIONS_HISTORY_ID
      FROM ACTIONS_HISTORY
RIGHT JOIN CALL ON ACTIONS_HISTORY.CALL_ID = CALL.CALL_ID

由于某种原因,这不会删除任何额外的行,例如,一个调用返回两个实例,因为它有两个相关的操作。我正在犯的明显错误是什么?

编辑:此代码有效,但现在返回重复的行(不确定错误是什么)

SELECT
    MAX(ACTIONS_HISTORY_ID) ACTIONS_HISTORY_ID,
    CALL.CALL_ID,
    DESCRIPTION_OF_ACTION
FROM ACTIONS_HISTORY
RIGHT OUTER JOIN CALL ON ACTIONS_HISTORY.CALL_ID = CALL.CALL_ID
GROUP BY CALL.CALL_ID, DESCRIPTION_OF_ACTION

5 个答案:

答案 0 :(得分:1)

group by用于聚合,而不是删除重复项。如果要删除欺骗,请使用distinct

要获得最大值,您需要使用max聚合明确请求它。在这种情况下,您也不会按两列进行分组。如果您的数据确实以可预测的方式随时间增加,那么您可能需要更复杂的查询才能获得所需内容。

答案 1 :(得分:1)

正如Donnie所说,GROUP BY用于聚合。您需要在SELECT子句中使用聚合函数,例如

SELECT
    CALL.CALL_ID,
    MAX(ACTIONS_HISTORY_ID) ACTIONS_HISTORY_ID
...

如果您的ID单调增加,这将实现您的目标。

编辑:然后你应该只按CALL_ID分组

答案 2 :(得分:1)

我在这台电脑上没有安装Oracle,所以我无法测试,但以下情况应该可行。您将收到每个电话和最近的操作(具有最高日期)。我认为即使对于没有动作的呼叫,rn也会为1,但你必须进行测试。

with ranked as(
    SELECT CALL.CALL_ID
          ,ACTIONS_HISTORY_ID
          ,row_number() over(partition by CALL.CALL_ID 
                                 order by ACTIONS_HISTORY_DT desc) as rn
      FROM ACTIONS_HISTORY
    RIGHT JOIN CALL ON ACTIONS_HISTORY.CALL_ID = CALL.CALL_ID
)
select *
  from ranked
 where rn = 1;

答案 3 :(得分:0)

虽然其他人提到使用MAX()的序列越来越多,但如果可能的话,最好避免使用它。由于ACTIONS_HISTORY_DT具有实际日期值,因此这是一个更好的候选者(此列上的索引将有助于提高性能)。

如果序列在技术上不再按升序排列,则在序列中使用MAX()可能会在某些情况下破坏查询,超出开发人员的控制范围(例如,移动到集群数据库)。

此外,您还可以使用分析函数来减少自联接的需要。看到 About SQL Functions: Analytic Functions和FIRST_VALUE了解详情。

我建议这个查询:

  WITH recent_actions AS
      (SELECT DISTINCT ah.call_id,
         FIRST_VALUE(ah.actions_history_id) OVER 
          (PARTITION BY ah.call_id 
           ORDER BY ah.actions_history_dt DESC ROWS UNBOUNDED PRECEDING
          ) AS latest_action_id
       FROM actions_history ah)
   SELECT c.call_id, r.latest_action_id
     FROM call c
LEFT JOIN recent_actions r ON(r.call_id = c.call_id);

因为查询使用公用表表达式(CTE)来提取CALL_ID和最新的ACTIONS_HISTORY_ID,所以如果您需要查询中返回的历史记录中的更多列,则可以使用这些ID向ACTIONS_HISTORY添加另一个外连接: / p>

  WITH recent_actions AS
      (SELECT DISTINCT ah.call_id,
         FIRST_VALUE(ah.actions_history_id) OVER 
          (PARTITION BY ah.call_id 
           ORDER BY ah.actions_history_dt DESC ROWS UNBOUNDED PRECEDING
          ) AS latest_action_id
       FROM actions_history ah)
   SELECT c.call_id, r.latest_action_id, h.description, h.duration, h.caller_id
     FROM call c
LEFT JOIN recent_actions r ON(r.call_id = c.call_id)
LEFT JOIN actions_history h ON(h.actions_history_id = r.latest_action_id;

答案 4 :(得分:0)

我认为您正在寻找max() keep (dense_rank...)

with ACTIONS_HISTORY as(
        select 1  call_id  , 1 ACTIONS_HISTORY_id, 'found' DESCRIPTION_OF_ACTION from dual
        union
        select 1  call_id  , 2 ACTIONS_HISTORY_id, 'lost' DESCRIPTION_OF_ACTION from dual
        union
        select 2  call_id  , 3 ACTIONS_HISTORY_id, 'green' DESCRIPTION_OF_ACTION from dual
        union
        select 2  call_id  , 4 ACTIONS_HISTORY_id, 'red' DESCRIPTION_OF_ACTION from dual
        union
        select 3  call_id  , 5 ACTIONS_HISTORY_id, 'delta' DESCRIPTION_OF_ACTION from dual

) ,
"CALL" as(
        select 1 call_id  from dual
        union
        select 2 call_id  from dual
        union
        select 3 call_id  from dual
)
    SELECT 
           "CALL".CALL_ID,
              max(DESCRIPTION_OF_ACTION) keep (dense_rank last order by ACTIONS_HISTORY_ID) DESCRIPTION_OF_ACTION ,
           max(ACTIONS_HISTORY_ID ) max_ACTIONS_HISTORY_ID 
      FROM ACTIONS_HISTORY
           RIGHT JOIN "CALL" 
              ON ACTIONS_HISTORY.CALL_ID = "CALL".CALL_ID
        group by "CALL".CALL_ID;


CALL_ID                DESCRIPTION_OF_ACTION MAX_ACTIONS_HISTORY_ID 
---------------------- --------------------- ---------------------- 
1                      lost                  2                      
2                      red                   4                      
3                      delta                 5