SQL Server 2000の課金クエリに関するアドバイス
-
09-09-2019 - |
質問
私は、クエリに取り組んでいくつかのアドバイスを必要としています。デザインに、私はバックエンドでこれをinplementする必要があるため、私は、しかし、フロントエンド・アプリケーションでこれを扱うことができます。私は以下の持っている
CREATE TABLE [dbo].[openitems](
[id] [varchar](8) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[type] [char](5) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[date] [smalldatetime] NULL,
[amount] [decimal](9, 2) NULL,
[daysOpen] [smallint] NULL,
[balance] [decimal](9, 2) NULL
) ON [PRIMARY]
insert into openitems values('A12399','INV','2008-12-05',491.96,123)
insert into openitems values('A12399','INV','2008-12-12',4911.37,116)
insert into openitems values('A12399','INV','2008-12-05',3457.69,109)
上記の表には、顧客のために開いているすべての請求書を持っています。私は最も古い請求書(表中のdaysOpen列)から始まるこれらの請求書に支払いを適用する必要があります。私は$ 550.00の支払いを持っているのであれば、私は最初の123 daysOldと請求書にそれを適用させていただきます、それは491.96 $だ - と、そのレコードを更新$ 500($ 8.04残すが、その次の請求書に適用...とされる)(バランス0.00に表の列)と次に移動し、残りを加えます。 $ 4903.33を残すことになる$ 8.04 - それは4911.37 $になります。あるのでないバランスは、ループ終了を適用することが残っていない。
残高の列が今読んでください。
0 4903.33 3457.69
注:私は(約1万)表内のすべての顧客のためにこれを実行する必要があります。顧客が開いて約20請求書の平均を持っています。
おかげ
解決
次の点を考慮します:
のバランスをフルに適用されるいずれかでのお支払いには、バランスに一部適用される、またはバランスをoverpaysます。
さて、私たちは、すべてのバランスのために、これまでの請求書の累積的なバランスを見つけることができることを想像してみてください。それを想像するのではなく、のは、それをやらせます:
create view cumulative_balance as
select a.*,
(select sum( balance )
from openitems b
where b.id = a.id and b.type = a.type and a.daysOpen >= a.daysOpen)
as cumulative_balance
from openitems a;
今、私たちは、任意のIDとタイプ、およびストアの支払い以下の最初の累積的なバランスを見つけることができる、とdaysOpen、およびサーバー変数の累積収支ます。
次に、我々はdaysOpen <我々が得た=値は、ゼロにこれらすべての残高を設定する場合、そのIDおよびタイプを持つすべてのopenItemsを更新します。
は、その後、我々は、そのIDおよびタイプの最初の非ゼロバランスを見つけ、それがバランスだことがそのバランスを設定 - (支払い - 私たちは記憶された累積バランス)。過払いがありますならば、このバランスは正常にマイナスになります。
正しいクエリを使用すると、1つのステートメントで検索し、最初の更新を行うことができるでしょう。
2つの問題があります。一つは、あなたが最初に支払われるべき同一のIDとタイプとdaysOpen、2つ以上のalancesの、決定できないということです。あなたのテーブルにのユニークのIDを追加すると、これらのケースのためのタイブレーカとして機能します。
第二には、2回目の更新のためのクエリでそれを使用する累計残高を保存する必要があります。あなたが正しくあなたのテーブルを設計した場合、支払によって更新されませんでしたINVOICE_AMOUNT用の列、およびだった支払い列で、これはあなたの問題を解決するだろう。
より良いリファクタリング、2回の表、請求書用と支払いのための1つを持っているだろう。そして、ビューはちょうど未払い残高や過払いのリストを作成、累積支払額に累積残高を比較することで、すべての作業を行うことができます<。 / P>
実際に、私はイニシャルFMとの主要な住宅ローン保証会社のためだけに、このようなシステムを設計しました。それは(これがデフォルトに行っていた住宅ローンのためだった、実際には、保険会社)あなたが持っているもの、その残高の金額と割合、および複数の支払者の式の数から算出したよりも少し複雑だったことに請求しなければなりませんでしたdefauted住宅ローンあたりの他の規則に従って所定の順序ます。
こののすべて基本的に私が上に概説したものでした(100行程度)短いストアドプロシージャと、ビューで行われた。これらの規則により、請求書の請求を命じたビューを使用し、中(支払いを適用ビュー)、追加の支払いは保険会社に何日に請求するものを計算します。次いでだけ(現在の日付は、テスト目的のための任意の日付に、再びビューを使用して、設定することができた)現在の日付の請求書を生成します。
ストアドプロシージャ <;(私が書いた唯一のC ++では、SybaseのいずれかにOracleシステムからのデータを転送するには、OracleやSybaseのC APIを使用していました。皮肉なことに、私はC ++を書くために取得したいの約束ontehが仕事を取るのだということです) / P>
他のヒント
これはそれを行う必要があります。私は、ローカル変数を宣言したが、あなたは、ストアドプロシージャからパラメータことを作ることができます。私はまた、IDと日付が一意であるように思えませんので、一意の請求書を識別するために、テーブルにinvoice_idを追加しました。
DECLARE
@paid_amount DECIMAL(9, 2)
SET @paid_amount = 500
UPDATE
OI
SET
balance =
CASE
WHEN @paid_amount - SQ.running_total > balance THEN 0
ELSE balance - (@paid_amount - SQ.running_total)
END
FROM
dbo.OpenItems OI
INNER JOIN (
SELECT
I1.id,
I1.invoice_id,
I1.date,
ISNULL(SUM(I2.amount), 0) AS running_total
FROM
OpenItems I1
LEFT OUTER JOIN OpenItems I2 ON
I2.id = I1.id AND
I2.type = 'INV' AND
I2.daysopen > I1.daysopen
GROUP BY
I1.id,
I1.invoice_id,
I1.date
) AS SQ ON
SQ.id = OI.id AND
SQ.invoice_id = OI.invoice_id
WHERE
@paid_amount > SQ.running_total
これは1時間の努力でない限り...
これはグレードってこんなモンロジックがあると、アプリケーションのビジネス層に属しているようですね。
あなたはカーソルと2つのネストされたループのカップルを使用しなければならないでしょう。 (これは少し遅いかもしれない)
一つは、すべての支払いを読み取るために - 私は顧客を想定し、金額
次に、各顧客のために開いている項目のための別のカーソルを作成します。
行われるまで、最初のループは支払いを読み込みます。
そのループの中で最も古い順にソート顧客のオープン項目のための新しいカーソルをオープンします。
開いている各項目をループし、あなたが説明するように支払いを適用します。
その後、次のお支払いを取得します。
これ以上の支払いまで繰り返します。