5

複数の行に値を分散する簡単な方法はありますか?

たとえば、私のテーブルには

請求済み支払済み現在のタイプ
チャージ1000100
チャージ1000100
チャージ1000100
支払い02500
支払い0250

データはこの方法でインポートされますが、インポートされた支払いトランザクションに基づいて、そのトランザクションに必要なものを列Currentと列に入力する必要があります。Paid

Current各レコードの列のバランスを決定するクエリを作成する簡単な方法はありますか?

たとえば、250は最初の2つのレコードに100を適用し、次の2つのレコードに50を適用し、25は最後のレコードに適用されるためCurrent、テーブルの残高を更新した後の最終結果は次のようになります。

請求済み支払済み現在のタイプ
チャージ1001000
チャージ1001000
充電1007525
支払い02500
支払い0250

理想的には、カーソルを使用して各アイテムを個別に処理するのではなく、単一のクエリでこれを実行したいと思います。Row_Number()関数を使用して、2つのサブクエリを結合することでこれを実行しようとしていますが、ここで何かが不足していることがわかります。

これが私の最初の試みで、現在の残高の現在の合計を取得することになりました

;with cte(invoiced, paid, current)
as (
    select invoiced, paid, current
        , row_number() over (order by datecreated)
    from mytable
)

select t1.invoiced, t1.paid, sum(t2.invoiced - t2.paid) as [current]
from cte as t1
join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
group by t1.uid, t1.number, t1.rownum
order by t1.rownum

結果:

請求済みの支払済み現在
100 0100
100 0200
100 0300
0 250 50
0 25 25

これを行う方法があると確信していますが、今のところ私の脳はストライキをしているようで、解決策を考え出すことを拒否しています。

4

2 に答える 2

4

私は解決策を見つけたと思います

まず、支払い済みのトランザクションを請求済みのトランザクションにリンクする必要がないため、すべての支払いの合計のみが必要です。

select accountid, sum(paid)
from mytable
where type = 'Payment'
group by accountid

次に、現在の合計が支払われた合計より大きくなるまで、この値を各レコードに適用する必要があります。

これを行うために、現在の合計クエリを変更して、料金と支払いの両方を合計するのではなく、料金のみを合計するようにしました

;with cte(id, accountid, invoiced, paid, current)
as (
    select id, accountid, invoiced, paid, current
        , row_number() over (order by datecreated)
    from mytable
    where type = 'Charge'
)

select t1.id, t1.accountid, t1.invoiced, sum(t2.invoiced) as [runningTotalOfCharges]
from cte as t1
join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
group by t1.id, t1.accountid, t1.invoiced

これを支払いクエリに結合したので、合計支払い額、そのレコードまでの現在の請求額、および現在のレコードの請求額を含む行がたくさんあります。

そこからCASE、料金が全額支払われたのか、部分的に支払われたのか、まったく支払われなかったのかを判断するためのステートメントがPaid必要Currentでした。

select charged.Id, charged.AccountId, charged.Invoiced
    -- Use Case statements to determine if this payment is fully paid, partially paid, 
    -- or not paid at all, then determine Current and Paid based on that
    , case when totalpaid - runningtotal >= 0 then invoiced 
        when invoiced > abs(totalpaid - runningtotal) then invoiced + totalpaid - runningtotal
        else 0 end as [Paid]
    , case when totalpaid - runningtotal >= 0 then 0 
        when invoiced > abs(totalpaid - runningtotal) then abs(totalpaid - runningtotal)
        else invoiced end as [Current]
from 
(
    -- Running total query from above
    select t1.id, t1.accountid, t1.invoiced, sum(t2.invoiced) as [runningtotal]
    from cte as t1
    join cte as t2 on t1.number = t2.number and t2.rownum <= t1.rownum
    group by t1.id, t1.accountid, t1.invoiced
) as charged

inner join (
    -- Total Paid query from above
    select accountid, sum(paid) as totalpaid
    from mytable
    where type = 'Payment'
    group by accountid
) as paid on charged.number = paid.number

そして、最終結果は私が望むものです。これを列を介して実際のデータテーブルに結合し、値と値Idを更新する必要があります:)PaidCurrent

IdAccountId請求済み支払済み現在
1 1100100 0
2 1100100 0
3 1100 75 25
于 2012-09-06T18:29:47.357 に答える
0

有料列と現在の列の現在の合計と合計を計算してから、いくつかの計算を実行して現在の列の値を取得できます。私はそれを試してみましたが、最終的な値を考え出すために数学に行き詰まりました。簡単な方法ではありませんが、方法です。

DECLARE @myTable TABLE
(
    [TranId] INT,
    [Type] VARCHAR(10),
    [Invoiced] INT,
    [Paid] INT,
    [Current] INT,
    [SumPaid] INT,
    [SumCurrent] INT,
    [RunningPaid] INT,
    [RunningCurrent] INT
)

INSERT INTO @myTable SELECT 1, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 2, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 3, 'Charge', 100, 0, 100, null, null, null, null
INSERT INTO @myTable SELECT 4, 'Paid', 0, 250, 0, null, null, null, null
INSERT INTO @myTable SELECT 5, 'Paid', 0, 25, 0, null, null, null, null


UPDATE @myTable SET SumPaid = (SELECT SUM([Paid]) FROM @myTable)
UPDATE @myTable SET SumCurrent = (SELECT SUM([Current]) FROM @myTable)
UPDATE @myTable
SET 
    [RunningPaid] = full_running_total_set.[RunningPaid], 
    [RunningCurrent] = full_running_total_set.[RunningCurrent]
FROM @myTable
INNER JOIN
(
    SELECT
        TranId1,
        SUM([Paid]) AS [RunningPaid],
        SUM([Current]) AS [RunningCurrent]
    FROM
    (
        SELECT
            set2.[Paid],
            set2.[Current],
            set1.[TranId] AS [TranId1],
            set2.[TranId] AS [TranId2]
        FROM @myTable set1
        INNER JOIN @myTable set2
            ON set1.[TranId] >= set2.[TranId]
    )running_total_set
    GROUP BY [TranId1]
)full_running_total_set
ON [TranId] = full_running_total_set.[TranId1]

SELECT * FROM @myTable
于 2012-09-06T18:02:07.677 に答える