我有两个表 - 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
答案 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()可能会在某些情况下破坏查询,超出开发人员的控制范围(例如,移动到集群数据库)。
此外,您还可以使用分析函数来减少自联接的需要。看到
我建议这个查询:
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