Oracle Group By Issue - PullRequest
       22

Oracle Group By Issue

2 голосов
/ 31 декабря 2010

Я борюсь с тем, что кажется легкой задачей (по крайней мере, для меня в MySQL / SqlServer!)

Я упросту проблему. Допустим, у меня есть следующая таблица:

Таблица ГОЛОСОВАНИЯ

ID  ID_IDEA DATE_VOTE   with ID_IDEA FK(IDEA.ID)
1   3       10/10/10
2   0       09/09/10
3   3       08/08/10
4   3       11/11/10
5   0       06/06/10
6   1       05/05/10

Я пытаюсь найти последние голоса, отданные за каждую отдельную идею, то есть я хочу вернуть только строки с ID 4, 2 и 6.

В Oracle кажется, что вы не можете использовать GROUP BY без использования таких функций, как SUM (), AVG и т. Д. Я немного запутался в том, как это должно работать.

Пожалуйста, сообщите,

Спасибо.

Ответы [ 4 ]

7 голосов
/ 31 декабря 2010
SELECT id,
       id_idea,
       date_vote
FROM   (SELECT id,
               id_idea,
               date_vote,
               Row_number() over (PARTITION BY id_idea 
                                      ORDER BY date_vote DESC NULLS LAST) AS rn
        FROM   VOTE) AS t
WHERE  rn = 1  
1 голос
/ 31 декабря 2010

Вы не должны обрабатывать такой запрос с аналитическими функциями, если вы можете сделать это простым агрегированием:

SQL> create table vote(id,id_idea,date_vote)
  2  as
  3  select 1, 3, date '2010-10-10' from dual union all
  4  select 2, 0, date '2010-09-09' from dual union all
  5  select 3, 3, date '2010-08-08' from dual union all
  6  select 4, 3, date '2010-11-11' from dual union all
  7  select 5, 0, date '2010-06-06' from dual union all
  8  select 6, 1, date '2010-05-05' from dual
  9  /

Table created.

SQL> select max(id) keep (dense_rank last order by date_vote) id
  2       , id_idea
  3       , max(date_vote) date_vote
  4    from vote
  5   group by id_idea
  6  /

        ID    ID_IDEA DATE_VOTE
---------- ---------- -------------------
         2          0 09-09-2010 00:00:00
         6          1 05-05-2010 00:00:00
         4          3 11-11-2010 00:00:00

3 rows selected.

По сравнению с аналитическим вариантом:

1) он работает (хорошоаналитическая также работает, если вы удалите «AS» в «AS t»)

2) она короче

3) она более понятна (хорошо, это субъективно)

4) он чуть более производительный, см .:

Это план для запроса агрегации:

Execution Plan
----------------------------------------------------------
Plan hash value: 2103353780

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     3 |    39 |     4  (25)| 00:00:01 |
|   1 |  SORT GROUP BY     |      |     3 |    39 |     4  (25)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| VOTE |     6 |    78 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

И это план для аналитического запроса:

Execution Plan
----------------------------------------------------------
Plan hash value: 781916126

---------------------------------------------------------------------------------
| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |     6 |   288 |     4  (25)| 00:00:01 |
|*  1 |  VIEW                    |      |     6 |   288 |     4  (25)| 00:00:01 |
|*  2 |   WINDOW SORT PUSHED RANK|      |     6 |    78 |     4  (25)| 00:00:01 |
|   3 |    TABLE ACCESS FULL     | VOTE |     6 |    78 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RN"=1)
   2 - filter(ROW_NUMBER() OVER ( PARTITION BY "ID_IDEA" ORDER BY
              INTERNAL_FUNCTION("DATE_VOTE") DESC  NULLS LAST)<=1)

С уважением, Роб.

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

Насколько я понимаю, вы ищете это:

SELECT id_idea, max(date_vote)
FROM vote
GROUP BY id_idea

Редактировать: если подумать, если вам нужно получить полный ряд:

SELECT v.*
FROM vote v
  JOIN (SELECT id_idea, max(date_vote) as max_date
        FROM vote
        GROUP BY id_idea) t
    ON t.id_idea = v.id_idea AND t.max_date = v.date_vote
0 голосов
/ 31 декабря 2010

Обычно я делаю это, используя первую или последнюю функцию . У него немного странная конструкция, которая может объяснить, почему он не очень часто используется. Обратите внимание, что, поскольку условие order by является детерминированным, max / min не имеет значения (но необходимо, потому что именно так строится функция.

select 
  max(id) keep (dense_rank last order by date_vote) as id,
  id_idea,
  max(date_vote)
  from vote
group by id_idea
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...