3

これは、グループごとに 1 つの最小値と最大値だけを気にする場合は比較的簡単ですが、問題は、さまざまな境界を見つけることです。データセットの例は次のとおりです。

BoundaryColumn GroupIdentifier
1A
3A
4A
7A
8B
9B  
11B  
13A
14A
15A
16A

SQL から必要なのは、次のような結果セットです。

min  max  groupid
1    7    A
8    11   B
13   16   A

基本的に、グループの各クラスターの境界を見つけます。

データは oracle11g または mysql のいずれかに格納されるため、どちらのプラットフォームにも構文を提供できます。

4

3 に答える 3

2

免責事項: フロントエンド言語を使用して、部分的な結果を照会し、このような処理を行う方がはるかに簡単です。それは言った...

次のクエリは、Oracle (分析クエリをサポートする) では機能しますが、MySQL (サポートしない) では機能しません。ここに SQL Fiddle があります。

WITH BoundX AS (
  SELECT * FROM (
    SELECT
     BoundaryColumn,
     GroupIdentifier,
     LAG(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLag,
     LEAD(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLead
    FROM MyTable
    ORDER BY BoundaryColumn
  )
  WHERE GIDLag IS NULL OR GroupIdentifier <> GIDLag
     OR GIDLead IS NULL OR GroupIdentifier <> GIDLead
)
SELECT MIN, MAX, GROUPID
FROM (
  SELECT
    BoundaryColumn AS MIN,
    LEAD(BoundaryColumn) OVER (ORDER BY BoundaryColumn) AS MAX,
    GroupIdentifier AS GROUPID,
    GIDLag,
    GIDLead
  FROM BoundX
)
WHERE GROUPID = GIDLead

これがロジックです。ここにはサブクエリが多すぎると感じているので、これを改善できるかもしれません...

このクエリは、前後のGroupIdentifier値を各行に取り込みます。

SELECT
 BoundaryColumn,
 GroupIdentifier,
 LAG(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLag,
 LEAD(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLead
FROM MyTable
ORDER BY BoundaryColumn

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

BoundaryColumn  GroupIdentifier  GIDLag  GIDLead
1                  A                         A
3                  A                A        A
4                  A                A        A
7                  A                A        B
8                  B                A        B
9                  B                B        B
11                 B                B        A
13                 A                B        A
14                 A                A        A
15                 A                A        A
16                 A                A

GIDLag= GIDLead=であるすべての行を取り除くロジックを追加GroupIdentifierすると、境界ができてしまいます。

WITH BoundX AS (
  SELECT * FROM (
    SELECT
     BoundaryColumn,
     GroupIdentifier,
     LAG(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLag,
     LEAD(GroupIdentifier) OVER (ORDER BY BoundaryColumn) AS GIDLead
    FROM MyTable
    ORDER BY BoundaryColumn
  )
  WHERE GIDLag IS NULL OR GroupIdentifier <> GIDLag
     OR GIDLead IS NULL OR GroupIdentifier <> GIDLead
)
SELECT
  BoundaryColumn AS MIN,
  LEAD(BoundaryColumn) OVER (ORDER BY BoundaryColumn) AS MAX,
  GroupIdentifier AS GROUPID,
  GIDLag,
  GIDLead
FROM BoundX

この追加により、結果は次のようになります。

MIN MAX GROUPID GIDLAG GIDLEAD
--- --- ------- ------ -------
  1   7 A              A
  7   8 A       A      B
  8  11 B       A      B
 11  13 B       B      A
 13  16 A       B      A
 16     A       A

最後に、GroupID = GIDLead. それがこの回答の上部にあるクエリです。結果は次のとおりです。

MIN MAX GROUPID
--- --- -------
  1   7 A
  8  11 B
 13  16 A
于 2013-10-16T18:50:38.987 に答える
1

別のアプローチ(オラクル)。ここでは、テーブルt1(テーブル) に対して発行されたクエリによって返された結果セットを単純に論理グループ ( grp) に分割します。GroupIdentifierの値が変化すると、それぞれの新しいグループが開始されます。

select min(q.BoundaryColumn)  as MinB
     , max(q.BoundaryColumn)  as MaxB
     , max(q.GroupIdentifier) as groupid
  from ( select s.BoundaryColumn
              , s.GroupIdentifier
              , sum(grp) over(order by s.BoundaryColumn) as grp
           from ( select BoundaryColumn
                       , GroupIdentifier
                       , case 
                           when GroupIdentifier <> lag(GroupIdentifier) 
                                                   over(order by BoundaryColumn) 
                           then 1
                         end as grp
                    from t1) s
       ) q
 group by q.grp

結果:

      MINB       MAXB  GROUPID
---------- ----------  -------
         1          7  A       
         8         11  B       
        13         16  A  

SQLfiddle デモ

于 2013-10-16T18:57:07.520 に答える
1

データの「実行」に関するこのサイトを見てください: http://www.sqlteam.com/article/detecting-runs-or-streaks-in-your-data

そのリンクで提供されている知識があれば、次のようなクエリを作成できます。

SELECT BoundaryColumn,
GroupIdentifier,
(
SELECT COUNT(*)
FROM Table T
WHERE T.GroupIdentifier <> TR.GroupIdentifier
AND T.BoundaryColumn <= TR.BoundaryColumn
) as RunGroup
FROM Table TR

この情報を使用して、「RunGroup」でグループ化し、GroupIdentifier と最小/最大 BoundaryColumn を選択できます。

編集:私は仲間の圧力を感じました.ここに私のバージョンの答えを持つSQLFiddleがあります: http://www.sqlfiddle.com/#!8/9a24c/4/0

于 2013-10-16T17:52:00.920 に答える