0

次のようなデータを格納するテーブルがあります(StarttimeとEndtimeはどちらもvarchar2です)。

StartTime EndTime
00:30      07:30
16:00      19:00
.           .
.           .
.           .

私がやりたいのは、これを対応する30分ごとの数値に変換することです。

00:00 becomes x1 
00:30 x2
01:00 x3
01:30 x4
..

真夜中(00:00はx1、23:30は48)

以下のSQLで私がしたこと:

Select StartTime, EndTime, 
    Case StartTime
        When '00:00' Then 'x1'
        When '00:30' Then 'x2' ....
    End StartTime_x
    Case EndTime
        When '00:00' Then 'x1'
        When '00:30' Then 'x2' ....
    End EndTime_x
From myTable    

それは私にこれを与えています:

StartTime, EndTime, StartTime_x, EndTime_x
16:00      19:00    x33          x39
19:00      20:00    x39          x41

私が達成しようとしているのはこれです:

StartTime, EndTime, StartTime_x, EndTime_x    Range
16:00      19:00    x33          x39           x33,x34,x35,x36,x37,x38,x39   
19:00      20:00    x39          x41           x39,x40,x41

starttime_x値とendtime_x値の間を移動して、それらの間にあるもののcsv値を作成するにはどうすればよいですか?

4

3 に答える 3

1

これがSQLの解決策です

テスト用に値を挿入して作成したテーブルは次のとおりです。

CREATE TABLE mytable AS
Select '00:30' As Starttime, '02:30' As Endtime FROM dual
Union All
Select '01:00' As Starttime, '04:00' As Endtime FROM dual
Union All
Select '00:00' As Starttime, '03:30' As Endtime FROM dual;

これがあなたが期待しているフォーマットでデータを返すためのクエリです

Select X.Starttime,X.Endtime,X.Starttime_X,X.Endtime_X, Listagg(X.Abc,',') Within Group (Order By X.Starttime) 
FROM
(
Select distinct a.*, 'x'||(LEVEL + (TO_NUMBER(substr(starttime_x,INSTR(starttime_x,'x',1)+1))) -1) as abc
From (Select StartTime, EndTime, 
    Case StartTime
        When '00:00' Then 'x1'
        When '00:30' Then 'x2' 
        When '01:00' Then 'x3'
        When '01:30' Then 'x4'
        When '02:00' Then 'x5'
        When '02:30' Then 'x6'
        When '03:00' Then 'x7'
        When '03:30' Then 'x8'
        When '04:00' Then 'x9'
        When '04:30' Then 'x10'
        When '05:00' Then 'x11'
        WHEN '05:30' THEN 'x12'
    End StartTime_x,
    Case EndTime
        When '00:00' Then 'x1'
        When '00:30' Then 'x2' 
        When '01:00' Then 'x3'
        When '01:30' Then 'x4'
        When '02:00' Then 'x5'
        When '02:30' Then 'x6'
        When '03:00' Then 'x7'
        When '03:30' Then 'x8'
        When '04:00' Then 'x9'
        When '04:30' Then 'x10'
        When '05:00' Then 'x11'
        WHEN '05:30' THEN 'x12'
    End Endtime_X
    From Mytable) A
    Connect By Level <= (To_Number(Substr(Endtime_X,Instr(Endtime_X,'x',1)+1)) - To_Number(Substr(Starttime_X,Instr(Starttime_X,'x',1)+1))) + 1
    ) X
    GROUP BY x.starttime, x.endtime,X.Starttime_X,X.Endtime_x;

出力は次のとおりです。

00:00   03:30   x1  x8  x1,x2,x3,x4,x5,x6,x7,x8
00:30   02:30   x2  x6  x2,x3,x4,x5,x6
01:00   04:00   x3  x9  x3,x4,x5,x6,x7,x8,x9
于 2013-03-01T09:05:07.280 に答える
1

まず、CASEステートメントで物事を複雑にしすぎています。代わりに数学を使用できます。具体的には、Oracleが日付演算を行うときに数値を返すという事実です。さらに、日付に変換することで、算術演算を正しく実行できます。そのような大きなCASEステートメントでタイプミスをするのは簡単です。つまり、すべてが間違っているということです。このソリューションは、特定の30分だけでなく、1日のいつでも処理します。

次のようにテーブルを設定した場合:

create table times ( starttime varchar2(5), endtime varchar2(5) );
insert into times values ( '00:30','07:30');
insert into times values ( '16:00','19:00');
insert into times values ( '19:00','20:00');

次のクエリは、ほとんどの方法でそこに到達します。

SQL> select starttime
          , endtime
          , trunc( ( to_date(starttime,'hh24:mi') 
                  - trunc(sysdate) ) * 48) + 1 as starttime_x
          , trunc( ( to_date(endtime,'hh24:mi') 
                  - trunc(sysdate) ) * 48) + 1 as endtime_x
       from times;

START ENDTI STARTTIME_X  ENDTIME_X
----- ----- ----------- ----------
00:30 07:30       1     16
16:00 19:00      33     39
19:00 20:00      39     41

次に、範囲内のすべての値のコンマ区切りリストを追加する必要があります。可能な限りこれを避けます...それはあなたにとってあまり役に立たないでしょう、そして表示するためだけに大丈夫でしょう。ただし、このデータはとの違いにstarttime_x含まれendtime_xているため、どのようなメリットがあるのか​​わかりません。

ただし、それを実行する必要があると仮定すると、開始範囲と終了範囲の間に行を生成してから、それらを集約する必要があります。

SQL> with the_times as ( 
  select starttime
       , endtime
       , trunc( ( to_date(starttime,'hh24:mi') 
               - trunc(sysdate) ) * 48) + 1 as starttime_x
       , trunc( ( to_date(endtime,'hh24:mi') 
                - trunc(sysdate) ) * 48) + 1 as endtime_x
    from times
         )
 , all_times as (
  select level as t
    from dual
 connect by level <= 48
         )
 select starttime, endtime
      , 'x' || starttime_x as starttime_x, 'x' || endtime_x as endtime_x
      , listagg('x' || t, ', ') within group ( order by t ) as range
   from ( select a.*, b.t
            from the_times a
           cross join all_times b
           where b.t between a.starttime_x and a.endtime_x
                 )
  group by starttime, endtime, 'x' || starttime_x, 'x' || endtime_x;

STARTTIME ENDTIME STA END RANGE
--------- ------- --- --- ---------------------------------------------------------------------------
00:30     07:30   x1  x16 x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16
16:00     19:00   x33 x39 x33, x34, x35, x36, x37, x38, x39
19:00     20:00   x39 x41 x39, x40, x41

ご覧のとおり、これは特にきれいではありません...

後で追加したことに注意してくださいx。数字に任意の文字を追加することは、あなたがより困難にしなければならない算術を作るのに役立つだけです。最後にそれを追加することはこれを回避する方法です。

于 2013-03-01T09:11:28.237 に答える
0

オラクル10gを使用している人のために、上記のベンの回答に基づいてここにソリューションを追加しました。

私は単にwm_concatでlistaggを変更しました:

with the_times as ( 
  select starttime
       , endtime
       , trunc( ( to_date(starttime,'hh24:mi') 
               - trunc(sysdate) ) * 48) + 1 as starttime_x
       , trunc( ( to_date(endtime,'hh24:mi') 
                - trunc(sysdate) ) * 48) + 1 as endtime_x
    from times
         )
 , all_times as (
  select level as t
    from dual
 connect by level <= 48
         )
select starttime, endtime
      , 'x' || starttime_x as starttime_x, 'x' || endtime_x as endtime_x
      , wm_concat('x' || t)  as range
   from ( select a.*, b.t
            from the_times a
           cross join all_times b
           where b.t between a.starttime_x and a.endtime_x
                 )
  group by starttime, endtime, 'x' || starttime_x, 'x' || endtime_x;
于 2013-03-01T14:10:05.770 に答える