2

次の Oracle クエリがあります。

SELECT id,
       DECODE(state, 'Open', state_in, NULL) AS open_in,
       DECODE(state, 'Not Open', state_in, NULL) AS open_out,
FROM (
       SELECT id,
              CASE WHEN state = 'Open'
                   THEN 'Open'
                   ELSE 'Not Open'
              END AS state,
              TRUNC(state_time) AS state_in
       FROM ...
     )

これにより、次のようなデータが得られます。

id  open_in              open_out
1   2009-03-02 00:00:00
1                        2009-03-05 00:00:00
1   2009-03-11 00:00:00
1                        2009-03-26 00:00:00
1                        2009-03-24 00:00:00
1                        2009-04-13 00:00:00

私が欲しいのは次のようなデータです:

id  open_in              open_out
1   2009-03-02 00:00:00  2009-03-05 00:00:00
1   2009-03-11 00:00:00  2009-03-24 00:00:00

つまり、id/のすべての一意のペアを保持しopen_inopen_outそれに続くopen_in. 特定の に対して任意の数の一意の値が存在する可能性があり、任意の数の一意の値open_inが存在する可能性があります。一意の/に一致する値がない可能性があります。その場合は、その行に対応する必要があります。idopen_outidopen_inopen_outopen_outnull

LAGここでは、おそらくまたはという分析関数LEADが役立つと思います。おそらく私はMINで使用する必要がありPARTITIONます。

4

2 に答える 2

3

もう少し簡単にできます。まず、サンプル テーブルを作成しましょう。

SQL> create table mytable (id,state,state_time)
  2  as
  3  select 1, 'Open', date '2009-03-02' from dual union all
  4  select 1, 'Closed', date '2009-03-05' from dual union all
  5  select 1, 'Open', date '2009-03-11' from dual union all
  6  select 1, 'Shut down', date '2009-03-26' from dual union all
  7  select 1, 'Wiped out', date '2009-03-24' from dual union all
  8  select 1, 'Demolished', date '2009-04-13' from dual
  9  /

Table created.

データは、select ステートメントの出力と同じです。

SQL> SELECT id,
  2         DECODE(state, 'Open', state_in, NULL) AS open_in,
  3         DECODE(state, 'Not Open', state_in, NULL) AS open_out
  4  FROM (
  5         SELECT id,
  6                CASE WHEN state = 'Open'
  7                     THEN 'Open'
  8                     ELSE 'Not Open'
  9                END AS state,
 10                TRUNC(state_time) AS state_in
 11         FROM mytable
 12       )
 13  /

        ID OPEN_IN             OPEN_OUT
---------- ------------------- -------------------
         1 02-03-2009 00:00:00
         1                     05-03-2009 00:00:00
         1 11-03-2009 00:00:00
         1                     26-03-2009 00:00:00
         1                     24-03-2009 00:00:00
         1                     13-04-2009 00:00:00

6 rows selected.

そして、少し簡単なクエリを次に示します。

SQL> select id
  2       , min(case when state = 'Open' then state_time end)  open_in
  3       , min(case when state != 'Open' then state_time end) open_out
  4    from ( select id
  5                , state
  6                , state_time
  7                , max(x) over (partition by id order by state_time) grp
  8             from ( select id
  9                         , state
 10                         , state_time
 11                         , case state
 12                           when 'Open' then
 13                             row_number() over (partition by id order by state_time)
 14                           end x
 15                      from mytable
 16                  )
 17         )
 18   group by id
 19       , grp
 20   order by id
 21       , open_in
 22  /

        ID OPEN_IN             OPEN_OUT
---------- ------------------- -------------------
         1 02-03-2009 00:00:00 05-03-2009 00:00:00
         1 11-03-2009 00:00:00 24-03-2009 00:00:00

2 rows selected.

よろしく、ロブ。

于 2010-05-20T20:21:47.690 に答える
1

Stack Overflowはインスピレーションを与えるものでなければならないと思います。少なくとも、より明確に考えるのに役立ちます。一日中このことに苦労した後、私はついにそれを手に入れました:

SELECT id,
       open_in,
       open_out
FROM (
       SELECT id,
              open_in,
              LAG(open_out, times_opened) OVER (PARTITION BY id
                                                ORDER BY open_out DESC
                                                NULLS LAST) AS open_out
       FROM (
              SELECT id,
                     open_in,
                     open_out,
                     COUNT(DISTINCT open_in) OVER (PARTITION BY id)
                       AS times_opened
              FROM (
                     SELECT id,
                            DECODE(state, 'Open', state_in, NULL) AS open_in,
                            DECODE(state, 'Not Open', state_in, NULL)
                              AS open_out
                     FROM (
                            SELECT id,
                                   CASE WHEN state = 'Open'
                                        THEN 'Open'
                                        ELSE 'Not Open'
                                   END AS state,
                                   TRUNC(au_time) AS state_in
                            FROM ...
                          )
                   )
            )
     )
WHERE open_in IS NOT NULL

更新:これは完全には機能しないようです。私の質問の例では問題なく動作しますが、一意idのが複数ある場合、LAG内容がシフトし、日付が常に一致するとは限りません。:(

于 2010-05-20T19:55:52.537 に答える