3

与えられたデータ:

 inventory_num_id        inventory_group_id             num   code
         9681066                 100003894             211      E
         9679839                 100003894             212      E
         9687165                 100003894             213      E
         9680883                 100003894             214      I
         9710863                 100003894             515      E
         9681246                 100003894             516      E
         9682695                 100003894             517      E
         9681239                 100003894             518      E
         9685409                 100003894             519      E
         9679843                 100003894             520      C
         9679844                 100003894             521      C
         9714882                 100003894             522      E
         9679845                 100003894             523      I
         9681211                 100003894             524      E
         9681216                 100003894             525      E
         9682696                 100003894             526      E
         9681227                 100003894             527      E

結果の例は次のようになります。

inventory_group_id   code start  end 
------------------   ---- -----  ---- 
         100003894      E   211   213
         100003894      I   214
         100003894      E   515   519
         100003894      C   520   521
         100003894      E   522
         100003894      I   523
         100003894      E   524   527

開始を最小値、終了値を最大値にするには、どの演算子を使用する必要がありますか?そして、終わり(最大)が提示されるべきではないときに私が何をすべきかを説明していただけますか?

どういうわけか、そこでGROUP BY句を使用できますか?

4

3 に答える 3

1

私はこれをMSSQLサーバーでテストしましたが、オラクルでも機能すると思います。

select max(inventory_group_id) inventory_group_id,max(code) Code ,min(num) minNum,max(num) maxNum

from
(
select inventory_group_id,inventory_num_id,code,num,
      (select min(num) from DATA where num>
             (select max(num) from DATA where DATA.num<a.num and code<>a.code) 
      ) as minNum
from DATA a
) A

group by minNum
order by 3
于 2012-08-03T06:47:43.550 に答える
1

アン、SQLのダークサイドに注意してください。それを行うには複数の方法があります。答えは次のとおりです。

SELECT a.inventory_group_id,
   a.code,
  a.num        AS "start",
  decode(b.num,a.num,null,b.num) AS "end" FROM
  ( SELECT inventory_num_id,inventory_group_id,code,num
         , ROW_NUMBER() OVER (PARTITION BY inventory_group_id,code ORDER BY num) AS rn
    FROM inventory_num  a
    WHERE NOT EXISTS
          ( SELECT * 
            FROM inventory_num  prev
            WHERE prev.inventory_group_id = a.inventory_group_id
            and  PREV.CODE = a.code
              AND prev.num = a.num - 1
          ) 
  )  a
JOIN
  ( SELECT  inventory_num_id,inventory_group_id,code, num 
         , ROW_NUMBER() OVER (PARTITION BY inventory_group_id,code ORDER BY num) AS rn
    FROM inventory_num  a
    WHERE NOT EXISTS
          ( SELECT * 
            FROM inventory_num  next
            WHERE next.inventory_group_id = a.inventory_group_id
            and  next.CODE = a.code
              AND next.num = a.num + 1
          )
  )  b
ON  b.inventory_group_id = a.inventory_group_id and b.code = a.code
AND b.rn  = a.rn
order by 3;
于 2012-08-03T06:04:35.340 に答える
1

gelonsoftが指摘したように、これを行うには多くの方法があります。でも、テーブルにぶつかるのは一度だけにしたいです。これは私の現在のお気に入りであり、このサイトで最初に見つけた方法、おそらくこの回答に基づいています(そして、これらの質問の中にもっと多くのアプローチが見つかるかもしれません:

select inventory_group_id, code, start_num,
    case when end_num = start_num then null else end_num end as end_num
from (
    select inventory_group_id, code, min(num) as start_num, max(num) as end_num
    from (
        select inventory_group_id, num, code,
            row_number() over (order by num)
              - row_number() over (partition by code order by num) as chain
        from inventory_num
    )
    group by inventory_group_id, code, chain
)
order by 1,3;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527

code内部選択は、値と値に基づいて人工的なグループ化を作成することにより、すべての作業をnum実行します。それを単独で実行して、実行内容を確認します。次のクエリは、グループを折りたたんで、num各人工グループの最低値と最高値を見つけることです。最後の外部クエリは、チェーンにリンクが1つしかない場合、つまり、とが同じである場合にend値を作成することです。nullstartend

あなたが言っていないのは、num値が連続している必要があるかどうかです。とを使用してレコードを追加するcode='I'num=216、同じ数の出力が得られますが、間に値214-216がない場合でも、1つのチェーンとして扱われます。215

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214        216
...

row_number()私はそれを考慮に入れてそれらを別々のチェーンとして扱うためにこの方法をどのように適応させるかを理解していません-それを単純に保ちながらそれができるかどうかを見たいと思います。与えられた他の答えでも同じことが起こります。しかし、それがあなたにとって重要かどうかはわかりません。

もしそうなら、これは一度だけテーブルにヒットする別のバージョンです。かなり複雑で、この形式では、連続していないnum値と同じ潜在的な問題があります。

select distinct inventory_group_id, code,
    case
        when prev_code = code then lag(num) over (order by rn)
        else num
    end as start_num,
    case
        when next_code != code and prev_code != code then null
        when next_code = code then lead(num) over (order by rn)
        else num
    end as end_num
from (
    select inventory_group_id, num, code, prev_code, next_code,
        rownum as rn
    from (
        select inventory_group_id, num, code,
            lag(code) over (partition by inventory_group_id
                order by num) as prev_code,
            lead(code) over (partition by inventory_group_id
                order by num) as next_code
        from inventory_num
    )
    where (prev_code is null or code != prev_code)
        or (next_code is null or code != next_code)
    order by 1,2,3
)
order by 1,3,2;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527

内部クエリはテーブルから選択し、分析関数leadlag 分析関数を使用して、各行の両側のコードを検索します。

次のクエリ出力では、次の行と前の行の両方と同じコードを持つ行が除外されます。つまり、途切れないチェーンの真ん中にあるものすべてです。つまり、各チェーンは最大2行に折りたたまれ、numそのチェーンの開始値と終了値が含まれます。

外側のクエリのステートメントは、を使用しcaseて、各チェーンの両方の行を同じように見せます。行が1つしかない場合(たとえば)、2番目の最初の句が最終値になります。これはあなたが望むと言ったものです。次に、作成された重複を削除します。leadlag214whencasenulldistinctcase

クエリの各レベルを個別に実行して、クエリが何をしているのかを確認し、前のレベルに対して何をしているのかを理解することをお勧めします。

code='I'私が言ったように、私がとで行を導入した場合、これは同じ潜在的な問題を抱えていnum=216ます:

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214        216
...

この方法を採用することで、これを2つのチェーンに分割できますが、num値と値を追跡して比較する必要があるため、少し複雑になりcodeます。

select distinct inventory_group_id, code,
    case
        when prev_num is null then num
        when prev_code = code then lag(num) over (order by rn)
        else num
    end as start_num,
    case
        when next_code != code and prev_code != code then null
        when next_code is null then num
        when next_num is null then null
        when next_code = code then lead(num) over (order by rn)
        else num
    end as end_num
from (
    select inventory_group_id, num, code, prev_code, next_code,
        case
            when prev_num != num - 1 then null
            else prev_num
        end as prev_num,
        case
            when next_num != num + 1 then null
            else next_num
        end as next_num,
        rownum as rn
    from (
        select inventory_group_id, num, code,
            lag(code) over (partition by inventory_group_id
                order by num) as prev_code,
            lead(code) over (partition by inventory_group_id
                order by num) as next_code,
            lag(num) over (partition by inventory_group_id
                order by num) as prev_num,
            lead(num) over (partition by inventory_group_id
                order by num) as next_num
        from inventory_num
    )
    where (prev_code is null or code != prev_code)
        or (next_code is null or code != next_code)
        or (prev_num is null or num != prev_num + 1)
        or (next_num is null or num != next_num - 1)
    order by 1,2,3
)
order by 1,3,2;

INVENTORY_GROUP_ID C  START_NUM    END_NUM
------------------ - ---------- ----------
         100003894 E        211        213
         100003894 I        214
         100003894 I        216
         100003894 E        515        519
         100003894 C        520        521
         100003894 E        522
         100003894 I        523
         100003894 E        524        527
于 2012-08-03T16:55:12.840 に答える