2015-06-29 8 views
2

У меня есть мнение (в Oracle), как показано ниже, который присоединился из трех таблиц:Группа колонок на основе Time Range

Col1 Col2 Time 
==== ===== ===== 
txt1 same0 10:50 
txt2 same0 10:51 
txt3 same0 16:30 
txt4 same0 10:54 
txt5 same1 15:15 
txt6 same2 16:31 
txt7 same3 08:05 
txt8 same3 08:07 

Я хочу, чтобы запрос, который группа col2 данных, которые имеют время менее чем за 5 минут (например) и подсчет строк, сгруппированных вместе. Таким образом, результат запроса должен выглядеть следующим образом:

Col1    Col2 Time    Count 
====    ===== =====    ===== 
txt1,txt2,txt4 same0 10:50,10:51,10:54 3 
txt3    same0 16:30    1 
txt5    same1 15:15    1 
txt6    same2 16:31    1 
txt7,txt8  same3 08:05,08:07   2 

Time колонок тип данные DATE но упрощен здесь для лучшего понимания.

Edit:

В приведенном ниже (из комментариев) ситуации, максимальное Count 5 полезно. Например:

Col1 Col2 Time 
==== ===== ===== 
txt1 same0 10:50 
txt2 same0 10:51 
txt3 same0 10:52 
txt4 same0 10:53 
txt5 same0 10:54 
txt6 same0 10:55 
txt7 same0 10:56 

Оно должно быть:

Col1      Col2 Time       Count 
====      ===== =====       ===== 
txt1,txt2,txt3,txt4,txt5 same0 10:50,10:51,10:52,10:53,10:54 5 
txt6,txt7     same0 10:55,10:56      2 
+2

Что бы группирование быть для 10: 48,10: 49,10: 50, 10:51, 10:52, 10:53, 10:54? –

+0

также будет сгруппирован 16:30, 16:31 и 15:15? Как и все от 0 до 5 минут, все с 5,01 до 10 минут, все с 10,01 до 15 и все от 15-20 и т. Д. ...? –

+0

@DavidAldridge Хороший отзыв, спасибо. В ситуации, о которой вы упомянули, я думаю, что максимум 5 баллов для этого хорош. Так что это должно быть 10: 48,10: 49,10: 50,10: 51,10: 52 в одной строке и 10:53, 10:54 в другой строке. –

ответ

1

SQL Fiddle

Если вы хотите сгруппировать значения с интервалом в 5 минут (например, 10: 45-10: 49, 10: 50-10: 54, 10: 55-11: 00 и т. Д.), То вы можете сделать:

Oracle 11g R2 Настройка схемы:

CREATE TABLE TEST (Col1, Col2, Time) AS 
      SELECT 'txt01', 'same0', TO_DATE('2015-06-29 10:49', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt02', 'same0', TO_DATE('2015-06-29 10:50', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt03', 'same0', TO_DATE('2015-06-29 10:51', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt04', 'same0', TO_DATE('2015-06-29 10:52', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt05', 'same0', TO_DATE('2015-06-29 10:53', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt06', 'same0', TO_DATE('2015-06-29 10:54', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt07', 'same0', TO_DATE('2015-06-29 10:55', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt08', 'same0', TO_DATE('2015-06-29 10:56', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt09', 'same0', TO_DATE('2015-06-29 16:30', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt10', 'same1', TO_DATE('2015-06-29 15:15', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt11', 'same2', TO_DATE('2015-06-29 16:31', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt12', 'same3', TO_DATE('2015-06-29 08:05', 'YYYY-MM-DD HH24:MI') FROM DUAL 
UNION ALL SELECT 'txt13', 'same3', TO_DATE('2015-06-29 08:07', 'YYYY-MM-DD HH24:MI') FROM DUAL 

Запрос 1:

SELECT LISTAGG(Col1, ',') WITHIN GROUP (ORDER BY Time) AS Col1, 
     Col2, 
     LISTAGG(TO_CHAR(Time, 'HH24:MI'), ',') WITHIN GROUP (ORDER BY Time) AS Time, 
     COUNT(1) AS "Count" 
FROM TEST 
GROUP BY 
     Col2, 
     TRUNC(Time), 
     FLOOR((TO_NUMBER(TO_CHAR(Time, 'HH24')) * 60 + TO_NUMBER(TO_CHAR(Time, 'MI')))/5) 

Results:

|       COL1 | COL2 |       TIME | Count | 
|-------------------------------|-------|-------------------------------|-------| 
|       txt01 | same0 |       10:49 |  1 | 
| txt02,txt03,txt04,txt05,txt06 | same0 | 10:50,10:51,10:52,10:53,10:54 |  5 | 
|     txt07,txt08 | same0 |     10:55,10:56 |  2 | 
|       txt09 | same0 |       16:30 |  1 | 
|       txt10 | same1 |       15:15 |  1 | 
|       txt11 | same2 |       16:31 |  1 | 
|     txt12,txt13 | same3 |     08:05,08:07 |  2 | 

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

Oracle 11g R2 схему Установка:

CREATE TYPE TEST_GROUP_OBJ AS OBJECT(
    Col1 VARCHAR2(54), -- 5 * Length of Col1 + 4 
    Col2 VARCHAR2(10), -- Length of Col2 
    Time VARCHAR2(29) -- 5 * Length of 'HH:MI' + 4 
) 
/
CREATE TYPE TEST_GROUP_TAB AS TABLE OF TEST_GROUP_OBJ 
/
CREATE FUNCTION getFiveMinuteGroupings 
RETURN TEST_GROUP_TAB PIPELINED 
AS 
    TYPE TEST_TAB IS TABLE OF TEST%ROWTYPE; 
    t_test_tab TEST_TAB; 
    v_time  TEST.TIME%TYPE; 
    v_grp  TEST_GROUP_OBJ := TEST_GROUP_OBJ(NULL, NULL, NULL); 
    v_count NUMBER(1,0); 
BEGIN 
    SELECT * 
    BULK COLLECT INTO t_test_tab 
    FROM TEST 
    ORDER BY Col2, Time; 

    IF t_test_tab.COUNT = 0 THEN 
    RETURN; 
    END IF; 

    v_time  := t_test_tab(1).TIME; 
    v_grp.COL1 := t_test_tab(1).COL1; 
    v_grp.COL2 := t_test_tab(1).COL2; 
    v_grp.TIME := TO_CHAR(t_test_tab(1).TIME, 'HH24:MI'); 
    v_count := 1; 

    FOR i IN 2 .. t_test_tab.COUNT LOOP 
    IF t_test_tab(i).COL2 = v_grp.COL2 
     AND t_test_tab(i).TIME <= v_time + INTERVAL '5' MINUTE 
     AND v_count < 5 
    THEN 
     v_grp.COL1 := v_grp.COL1 || ',' || t_test_tab(i).COL1; 
     v_grp.TIME := v_grp.TIME || ',' || TO_CHAR(t_test_tab(i).TIME, 'HH24:MI'); 
     v_count := v_count + 1; 
    ELSE 
     PIPE ROW(v_grp); 
     v_time  := t_test_tab(i).TIME; 
     v_grp.COL1 := t_test_tab(i).COL1; 
     v_grp.COL2 := t_test_tab(i).COL2; 
     v_grp.TIME := TO_CHAR(t_test_tab(i).TIME, 'HH24:MI'); 
     v_count := 1; 
    END IF; 
    END LOOP; 
    PIPE ROW(v_grp); 
END; 
/

Запрос 2:

SELECT * 
FROM TABLE(getFiveMinuteGroupings()) 

Results:

|       COL1 | COL2 |       TIME | 
|-------------------------------|-------|-------------------------------| 
| txt01,txt02,txt03,txt04,txt05 | same0 | 10:49,10:50,10:51,10:52,10:53 | 
|    txt06,txt07,txt08 | same0 |    10:54,10:55,10:56 | 
|       txt09 | same0 |       16:30 | 
|       txt10 | same1 |       15:15 | 
|       txt11 | same2 |       16:31 | 
|     txt12,txt13 | same3 |     08:05,08:07 | 
+0

Блестящий! Благодарю. Только один вопрос. Есть ли способ начать с 10:49 до 10:53 и в другой строке 10:54 до 10:56? Я имею в виду, начиная с момента начала. Конечно, это не важно, я просто попросил лучше понять. И может понадобиться в некоторой ситуации. Потому что таким образом у нас есть 3 строки «same0» вместо 4. –

+1

@JohnCroneh Обновлено – MT0

1

Этот запрос дал мне желаемый результат:

select 
    listagg(col1, ', ') within group (order by col1) col1, col2, 
    listagg(to_char(ttime, 'hh24:mi'), ', ') within group (order by ttime) as ttime, 
    count(1) cnt 
    from (
    select col1, col2, ttime, trunc(ttime, 'dd') + floor(to_char(ttime,'sssss')/300)/288 tmp 
     from test) 
    group by col2, tmp 

SQLFiddle demo

Смежные вопросы