2015-06-29 77 views
2

我有(在Oracle)的圖一列像下面已經從三個表加入:組基於時間段

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但在這裏簡化了更好的理解。

編輯:

在下面(從評論)的情況下,最大的5 Count是有用的。例如:

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