2

テーブルAに以下のデータがあり、これを1 つの計算列と共にテーブルBに挿入する必要があります。

表 A:

Account_No |  Balance   |  As_on_date  
1001       |-100        |  1-Jan-2013  
1001       |-150        |  2-Jan-2013  
1001       | 200        |  3-Jan-2013  
1001       |-250        |  4-Jan-2013  
1001       |-300        |  5-Jan-2013  
1001       |-310        |  6-Jan-2013

表 B:

表 B には、残高がマイナスになった日付と、マイナスになった日付が表示されます。

したがって、2013 年 1 月 6 日の場合、このテーブルには以下のデータが表示されます。

Account_No |  Balance   |  As_on_date   | Days_passed | Start_date   
1001       |    -310    |    6-Jan-2013 |    3        |     4-Jan-2013

ここでは、古いエントリからではなく、最近残高がマイナスになった日を何日も指定しないでください。

経過した日数と、残高がマイナスになった開始日を取得する SQL クエリを作成する必要があります。

分析関数を使用してクエリを作成しようとしましたLagが、成功しません。

LAG関数を使用してトラバース バックすることにより、負の残高の最初のインスタンスを確認するにはどうすればよいですか?

関数でさえfirst_value試してみましたが、負の値に基づいて分割する方法がわかりませんでした。

これに関するヘルプや指示は本当に役に立ちます。

4

3 に答える 3

2

これは、分析関数を使用してこれを達成する方法です。

INSERT INTO tableb
   WITH tablea_grouped1
        AS (SELECT account_no,
                   balance,
                   as_on_date,
                   SUM (CASE WHEN balance >= 0 THEN 1 ELSE 0 END)
                      OVER (PARTITION BY account_no ORDER BY as_on_date)
                      grp
              FROM tablea),
        tablea_grouped2
        AS (SELECT account_no,
                   balance,
                   as_on_date,
                   grp,
                   LAST_VALUE (
                      balance)
                   OVER (
                      PARTITION BY account_no, grp
                      ORDER BY as_on_date
                      ROWS BETWEEN UNBOUNDED PRECEDING
                           AND     UNBOUNDED FOLLOWING)
                      closing_balance
              FROM tablea_grouped1
             WHERE balance < 0 
               AND grp != 0 --keep this, if starting negative balance is to be ignored
           )
     SELECT account_no,
            closing_balance,
            MAX (as_on_date),
            MAX (as_on_date) - MIN (as_on_date) + 1,
            MIN (as_on_date)
       FROM tablea_grouped2
   GROUP BY account_no, grp, closing_balance
   ORDER BY account_no, MIN (as_on_date);
  • まず、SUM を分析関数として使用して、0 未満の連続する残高にグループ番号を割り当てます。
  • 次に、LAST_VALUE 関数を使用して、各グループの最後の -ve 残高を見つけます
  • 最後に、結果は各グループに基づいて集計されます。MAX(date) は最後の日付、MIN(date) は開始日、そして 2 つの差が日数を示します。

sqlfiddleでのデモ。

于 2013-09-14T12:43:44.117 に答える
2

Try this and use gone_negative to computing specified column value for insert into another table:

select temp.account_no,
       temp.balance,
       temp.prev_balance,
       temp.on_date,
       temp.prev_on_date,
       case
         WHEN (temp.balance < 0 and temp.prev_balance >= 0) THEN
          1
         else
          0
       end as gone_negative
  from (select account_no,
               balance,
               on_date,
               lag(balance, 1, 0) OVER(partition by account_no ORDER BY account_no) prev_balance,
               lag(on_date, 1) OVER(partition by account_no ORDER BY account_no) prev_on_date
          from tblA
         order by account_no) temp;

Hope this helps pal.

于 2013-09-14T13:11:18.850 に答える
0

これはそれを行う途中です。

  1. my_table残高がプラスのレコードをすべて選択します。
  2. 自己結合を実行しas_on_date、現在の行よりも大きいがamounts負の値を持つすべてのレコードを取得します
  3. これらを取得したら、 isの現在の行と前の行の間の行WHEREを切り捨てます。次に、結果をフィルタリングしますdate differencerowas_on_date> 1outer sub query
  4. Finalは行をグループ化し、グループ化されたフィルタリングされた行の値をselect取得します。min, max

クエリ:

SELECT 
      account_no,
      min(case when row_number = 1 then balance end) as balance,
      max(mt2_date) as As_on_date,
      max(mt2_date) - mt1_date as Days_passed,
      min(mt2_date)  as Start_date
    FROM
      (
        SELECT 
         *,
         MIN(break_date) OVER( PARTITION BY mt1_date ) AS min_break_date,
         ROW_NUMBER() OVER( PARTITION BY mt1_date ORDER BY mt2_date desc ) AS row_number
        FROM 
          (
            SELECT 
              mt1.account_no,
              mt2.balance,
              mt1.as_on_date as mt1_date,
              mt2.as_on_date as mt2_date,
              case when mt2.as_on_date - lag(mt2.as_on_date,1) over () > 1 then mt2.as_on_date end as break_date
            FROM
              my_table mt1
              JOIN my_table mt2 ON ( mt2.balance < mt1.balance AND mt2.as_on_date > mt1.as_on_date ) 
            WHERE 
              MT1.balance > 0
            order by
              mt1.as_on_date,
              mt2.as_on_date ) sub_query
        ) T
    WHERE
      min_break_date is null 
      OR mt2_date < min_break_date
    GROUP BY
      mt1_date,
      account_no

SQLFIDDLE

テストするために、FIDDLEにさらにいくつかの行を追加しました

于 2013-09-14T15:04:10.910 に答える