Group By не работает в Oracle - PullRequest
       3

Group By не работает в Oracle

0 голосов
/ 08 декабря 2010

У меня есть две таблицы - 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 ]

1 голос
/ 08 декабря 2010

Как предположил Донни, GROUP BY предназначена для агрегирования.Вам нужно использовать агрегатную функцию в предложении SELECT, например,

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

Это позволит достичь вашей цели, если ваши идентификаторы будут монотонно увеличиваться.

РЕДАКТИРОВАТЬ: И тогда вам следует только группировать по CALL_ID

1 голос
/ 08 декабря 2010

У меня нет установки 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;
1 голос
/ 08 декабря 2010

group by для агрегации, а не удаления дубликатов.Если вы хотите удалить дубликаты, используйте distinct.

. Для получения максимума вам необходимо явно запросить его, используя агрегат max.В этом случае вы также не группируете по обоим столбцам.Если ваши данные со временем увеличиваются предсказуемым образом, вероятно, вам понадобится более сложный запрос, чтобы получить то, что вы хотите.

0 голосов
/ 09 декабря 2010

Я думаю, что вы ищете max () keep (dens_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  
0 голосов
/ 08 декабря 2010

Хотя другие упоминают об использовании MAX () с возрастающей последовательностью, лучше избегать этого, если это возможно.Поскольку у вас есть ACTIONS_HISTORY_DT с фактическим значением даты, этот вариант лучше использовать (и индекс в этом столбце будет способствовать повышению производительности).

Использование MAX () с последовательностью может привести к прерыванию запроса в некоторых обстоятельствах за пределамиконтроль разработчика (например, перемещение в кластеризованную базу данных), когда последовательности больше не находятся в техническом порядке в возрастающем порядке.

Кроме того, вы также можете использовать аналитические функции, чтобы уменьшить потребность в самосоединениях.См. О функциях SQL: аналитические функции и FIRST_VALUE на oracle.com для получения дополнительной информации.

Я бы предложил этот запрос:

  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, вы можете использовать эти идентификаторы для добавления другого внешнего соединения в ACTIONS_HISTORY, если вам нужно больше столбцов из истории, возвращаемой в запросе:

  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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...