4

私ができるようにしたいのは、IDが1つのグループにある時間の各「エピソード」の時間を合計し、NCからCおよびCからNCの最初のエピソード時間を取得し、NCからCへの最後のエピソード時間を取得することですおよび C から NC 下の表では、GRP_Time列を手動で追加しました。また、最終結果表を追加しました

これは私が体系的に生成しようとしているメトリックです。

ID    ASSign_ID  GRP      Time            GRP_Time   
11    1788       NC       6             
11    1802       NC       1               7
11    2995       C        7               7
11    5496       NC       11              11
11    6077       C        2 
11    6216       C        2
11    6226       C        4               8  
11    6790       NC       5               5
12    1234       C        6               6
12    2345       NC       1               
12    3456       NC       8               9
12    4567       C       11              11
14    6789       C        2 
14    7890       C        2
14    8900       C        4               8  
14    8904       NC       5               5

結果表

ID   First_ET_NC_C    First_ET_C_NC   LAST_ET_NC_C   LAST_ET_C_NC
11   7                7               11             8
12   9                6                9             6 
14   -                8                -             8
4

3 に答える 3

5

これを試して:

with seq as 
(    
  select tbl.*, 
      row_number() over(order by assign_id) rn  -- naturalized the order
  from tbl
),
grp as 
(
  select cr.*,          
     sum(case when cr.grp = pr.grp or pr.grp is null then 0 else 1 end)
     over(order by cr.rn) gn      
  from seq cr -- current row
  left join seq pr -- previous row
  on pr.rn = cr.rn - 1
)
,run as
(
  select grp.*,
      sum(time) over(partition by gn order by rn) as run_tot
  from grp
)
select 
   id, assign_id, grp, time,
   case when max(rn) over(partition by gn) <> rn then 
      null
   else
      run_tot
   end as run_total
from run r;

出力:

ID        ASSIGN_ID GRP       TIME      RUN_TOTAL
11        1788      NC        6         (null)
11        1802      NC        1         7
11        2995      C         7         7
11        5496      NC        11        11
11        6077      C         2         (null)
11        6216      C         2         (null)
11        6226      C         4         8
11        6790      NC        5         5

ライブテスト:http ://www.sqlfiddle.com/#!4 / faacc / 1


使い方:

ID        ASSIGN_ID GRP       TIME      RN        GN
11        1788      NC        6         1         0
11        1802      NC        1         2         0
11        2995      C         7         3         1
11        5496      NC        11        4         2
11        6077      C         2         5         3
11        6216      C         2         6         3
11        6226      C         4         7         3
11        6790      NC        5         8         4

GN基本的に、連続するgrpにグループ番号(列)を割り当てる必要があります。次に、そこからGNでパーティション化された現在の合計を実行できます

ここでクエリの進行状況を確認できます:http ://www.sqlfiddle.com/#!4 / faacc / 1

各ステップは、前のステップの上に構築されます。下にスクロールするだけで、ソリューションがどのように進行するかを確認できます


編集

レポートには各行の合計の実行が表示されず、最後の行にのみ表示されるため、クエリを短縮できます。代わりにsum(time) over(partition by gn order by rn) as run_tot、を実行できます。つまり、 ;sum(time) over(partition by gn) as run_totを削除します。order by rn次に、その行が最後の行であるかどうかを検出します。最後の行である場合は、を実行しsum overます。それ以外の場合はnullを表示します。

最終クエリ:

with seq as 
(

  select
  
     tbl.*, 
     row_number() over(order by assign_id) rn  -- naturalized the order
  from tbl
),
grp as 
(
  select 
   
     cr.*,
      
     sum(case when cr.grp = pr.grp or pr.grp is null then 0 else 1 end)
     over(order by cr.rn) gn
  
  from seq cr -- current row
  left join seq pr -- previous row
  on pr.rn = cr.rn - 1
)
select
     grp.*,

     case when max(rn) over(partition by gn) <> rn then -- if not last row
        null
     else -- if last row
        sum(time) over(partition by gn) 
     end as running_total
from grp;

ライブテスト:http ://www.sqlfiddle.com/#!4 / faacc / 7



編集

複数のIDについて、例:6790:

ID        ASSIGN_ID GRP       TIME
11        1788      NC        6
11        1802      NC        1
11        2995      C         7
11        5496      NC        11
11        6077      C         2
11        6216      C         2
11        6226      C         4
11        6790      NC        5
12        6790      NC        1
12        6791      NC        3
12        6792      NC        1
12        6793      NC        4
12        6794      C         1
12        6795      C         6
12        6797      C         8
13        6793      C         1
13        6794      C         4
13        6795      C         3

2つの類似したASSIGN_ID、たとえば6790がありますが、それはより大きなグループ(ID、11と12)に属しているため、これら2つのグループを分離するには、IDでそれらを分割する必要があります。

これが最後のクエリです。コメントに追加されたことに注意してください: http ://www.sqlfiddle.com/#!4/83789/2

with seq as 
(    
  select tbl.*, 

     -- added this: partition by id
     -- naturalized the order: rn       
     row_number() over(partition by id order by assign_id) rn  
  from tbl
)
,grp as 
(
  select cr.*,        

     -- added this: partition by cr.id
     sum(case when cr.grp = pr.grp then 0 else 1 end)
     over(partition by cr.id order by cr.rn) gn      
  from seq cr -- current row
  left join seq pr -- previous row
  on 
    pr.id = cr.id -- added this
    and pr.rn = cr.rn - 1
)
select id, assign_id, grp, time, 

     -- added this: partition by id
     case when max(rn) over(partition by id,gn) <> rn then 
        null
     else
        -- added this: partition by id
        sum(time) over(partition by id,gn) 
     end as running_total
from grp
order by id, rn;

出力:

ID        ASSIGN_ID GRP       TIME      RUNNING_TOTAL
11        1788      NC        6         (null)
11        1802      NC        1         7
11        2995      C         7         7
11        5496      NC        11        11
11        6077      C         2         (null)
11        6216      C         2         (null)
11        6226      C         4         8
11        6790      NC        5         5
12        6790      NC        1         (null)
12        6791      NC        3         (null)
12        6792      NC        1         (null)
12        6793      NC        4         9
12        6794      C         1         (null)
12        6795      C         6         (null)
12        6797      C         8         15
13        6793      C         1         (null)
13        6794      C         4         (null)
13        6795      C         3         8

それがどのように機能するか、IDとGNに注意してください:

ID        ASSIGN_ID GRP       TIME      RN        GN        RUNNING_TOTAL
11        1788      NC        6         1         1         (null)
11        1802      NC        1         2         1         7
11        2995      C         7         3         2         7
11        5496      NC        11        4         3         11
11        6077      C         2         5         4         (null)
11        6216      C         2         6         4         (null)
11        6226      C         4         7         4         8
11        6790      NC        5         8         5         5
12        6790      NC        1         1         1         (null)
12        6791      NC        3         2         1         (null)
12        6792      NC        1         3         1         (null)
12        6793      NC        4         4         1         9
12        6794      C         1         5         2         (null)
12        6795      C         6         6         2         (null)
12        6797      C         8         7         2         15
13        6793      C         1         1         1         (null)
13        6794      C         4         2         1         (null)
13        6795      C         3         3         1         8

ここでクエリの進行を参照してください:http ://www.sqlfiddle.com/#!4/83789/2


更新これを使用してみてください、それはより簡潔で読みやすいです:https ://stackoverflow.com/a/10629498

于 2012-05-16T17:55:36.287 に答える
1

次のクエリは、LAG()を使用しているため、Oracleでのみ使用できます。

SELECT Table1.ID, 
       Table1.ASSign_ID, 
       Table1.GRP, 
       Table1.TIME, 
       grpSum.GRP_TIME 
FROM   Table1 
       left join (SELECT ID, 
                         MAX(ASSIGN_ID) ASSIGN_ID, 
                         SUM(TIME)      GRP_TIME 
                  FROM   (SELECT ID, 
                                 ASSIGN_ID, 
                                 GRP, 
                                 TIME, 
                                 SUM(GC) over (PARTITION BY GRP ORDER BY ID, ASSIGN_ID ) g 
                          FROM   (SELECT ID, 
                                         ASSIGN_ID, 
                                         GRP, 
                                         TIME, 
                                         CASE 
                                           WHEN GRP = Lag(GRP) over (ORDER BY ID, ASSIGN_ID) 
                                               THEN  0 
                                               ELSE 1 
                                         END gc 
                                  FROM   TABLE1) a) b
                  GROUP  BY ID, 
                            GRP, 
                            g) grpSum 
         ON table1.ID = grpSum.ID 
            AND table1.ASSIGN_ID = grpSum.ASSIGN_ID 
ORDER BY Table1.ID, 
         Table1.ASSign_ID

デモ

ギャップと島のソリューションを説明するのは少し難しいですが、各部分が行うことは次のとおりです

  • 最も内側のクエリ「A」はLAGを使用して、「エピソード」の最初のアイテムに1を割り当て、その後、すべてのメンバーに0を割り当てます。

  • 次のクエリ「B」は、SUM OVERを使用して、「エピソード」の各メンバーに同じ識別子を割り当てます。GRPが異なる場合、同じ識別子が異なるエピソードに使用されることに注意してください

  • クエリgrpSumは、各「エピソード」の時間の合計を実行し、最大のAssing_IDを「エピソード」の最後の時間として識別します。

  • 次に、IDの元のテーブルを結合したままにして、投影を実行します。

マイケルのプログレッションデモンストレーションのアイデアを盗んでいます

ここでサブクエリの進行状況を確認できます (下にスクロール)

CASE MAX OVER注:Michealの回答のandテクニックを使用してSUM OVER、LEFTJOINおよびgrpSUMクエリを削除することもできます。

SELECT ID, 
       ASSIGN_ID, 
       GRP, 
       TIME, 
       CASE 
         WHEN Max(ASSIGN_ID) OVER (partition BY ID, GRP, G) = ASSIGN_ID THEN 
         SUM (TIME) OVER (partition BY ID, GRP, G) 
         ELSE NULL 
       END GRP_TIME 
FROM   (SELECT ID, 
               ASSIGN_ID, 
               GRP, 
               TIME, 
               Sum(GC) OVER (partition BY GRP ORDER BY ID, ASSIGN_ID ) g 
        FROM   (SELECT ID, 
                       ASSIGN_ID, 
                       GRP, 
                       TIME, 
                       CASE 
                         WHEN GRP = Lag(GRP) OVER (ORDER BY ID, ASSIGN_ID) THEN 
                         0 
                         ELSE 1 
                       END gc 
                FROM   TABLE1) a) b
    ORDER BY ID, 
             ASSign_ID

デモ

于 2012-05-16T17:26:32.287 に答える
0

行をソートするための適切な候補がないと仮定して、row_numberを使用するという以前の回答に非常に熱心です(実際、コードORDER BY NULLが行の物理的な順序に依存していることを明示するために、最初にコードの反復を行います) . データに自然な順序があることに気付いたとき、私はすでに白紙の状態から始めるべきでした。

id + assign_id は、行のパーティション分割と順序付けに自然に適合します。より単純なクエリを作成し、LAG を使用することができます。

これは、最も短くて簡単なクエリです: http://www.sqlfiddle.com/#!4/b6c14/3

with hm as -- headers marked
(
    select tbl.*,

      case when lag(grp) over(partition by id order by assign_id) = grp then 
        0 
      else 
        1 
      end mark_header

    from tbl
)
,grp as -- grouping
(
    select 
      hm.*,

      -- gn: group number
      sum(mark_header) over(partition by id order by assign_id) as gn
    from hm
)
select -- final query
    id, assign_id, grp, time,

    case when max(assign_id) over(partition by id,gn) = assign_id then
       sum(time) over(partition by id,gn) 
    else
       null
    end as running_total
from grp
order by id, assign_id;

出力:

ID        ASSIGN_ID GRP       TIME      RUNNING_TOTAL
11        1788      NC        6         (null)
11        1802      NC        1         7
11        2995      C         7         7
11        5496      NC        11        11
11        6077      C         2         (null)
11        6216      C         2         (null)
11        6226      C         4         8
11        6790      NC        5         5
12        6790      NC        1         (null)
12        6791      NC        3         (null)
12        6792      NC        1         (null)
12        6793      NC        4         9
12        6794      C         1         (null)
12        6795      C         6         (null)
12        6797      C         8         15
13        6793      C         1         (null)
13        6794      C         4         (null)
13        6795      C         3         8

それがどのように機能するか、ID と GNに注意してください。これは、現在の合計に基づいて構築する場所です。

ID        ASSIGN_ID GRP       TIME      MARK_HEADER  GN
11        1788      NC        6         1            1
11        1802      NC        1         0            1
11        2995      C         7         1            2
11        5496      NC        11        1            3
11        6077      C         2         1            4
11        6216      C         2         0            4
11        6226      C         4         0            4
11        6790      NC        5         1            5
12        6790      NC        1         1            1
12        6791      NC        3         0            1
12        6792      NC        1         0            1
12        6793      NC        4         0            1
12        6794      C         1         1            2
12        6795      C         6         0            2
12        6797      C         8         0            2
13        6793      C         1         1            1
13        6794      C         4         0            1
13        6795      C         3         0            1

ここで進行状況を参照してください: http://www.sqlfiddle.com/#!4/b6c14/3


Oracle に最適化できます (CASE WHEN の代わりに DECODE を使用): http://www.sqlfiddle.com/#!4/b6c14/6

with hm as -- headers marked
(
    select tbl.*,

      decode(lag(grp) over(partition by id order by assign_id), grp, 0, 1)
         as mark_header

    from tbl
)
,grp as -- grouping
(
    select 
      hm.*,

      sum(mark_header) over(partition by id order by assign_id) as gn
    from hm
)
select -- final query
    id, assign_id, grp, time,

    decode(max(assign_id) over(partition by id,gn), assign_id,           
       sum(time) over(partition by id,gn), null) as running_total 

from grp
order by id, assign_id;
于 2012-05-17T03:36:42.357 に答える