我需要解决一个查询的一些建议。我可以在前端应用程序但是解决这个问题,由于设计,我在后端到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,并移动到下一个和应用剩余。这将是$ 4911.37 - $ 8.04这会使$ 4903.33。由于没有留下任何的平衡被施加,退出循环。

在平衡柱现在应该读

0
4903.33
3457.69

请注意:我需要在表格中做到这一点为所有客户(约10,000)。一位顾客具有开放平均约20发票。

由于

有帮助吗?

解决方案

考虑如下:

付款要么完全适用于一个平衡,适用于部分的平衡,或高价从平衡。

现在,想象一下,我们可以发现,任何平衡,发票日期的累计余额。而不是想象,让我们做吧:

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;

现在,我们可以找到第一个累计余额小于或等于支付,对于任何标识和类型,并加以储存,并daysOpen,并在服务器变量累计余额。

然后,我们更新具有该ID和类型,其中daysOpen <=我们得到的值,所有这些余额设置成零。

所有openItems

随后,我们发现标识和类型的第一个非零平衡,并设置其资产负债是它的平衡 - (付款 - 我们存储的累计余额)。如果有一个多付,这种平衡将是正确负。

使用正确的查询,你就可以做的查找和第一次更新在一条语句。

有两个问题。其中之一是,你不能确定两个或两个以上alances使用相同的ID和类型,daysOpen,应先支付的。添加的唯一的ID给您的表将作为一个决胜的这些情况。

其次是需要保存累积余额使用它在查询用于第二更新。如果你正确地设计你的餐桌,与INVOICE_AMOUNT列不是由支付更新和支付列,这是,这将解决您的问题。

这是更好的重构将有两个表,一个是发票和一个用于支付:那么视图可以只完成所有的工作,通过比较累积余额累计支付,生产未付余额或超额支付的列表

其实,我只是设计这样一个系统的一个主要的抵押担保公司,英文缩写FM。这是一个比较复杂一点比你所拥有的,在余额从一数量和百分比,以及多个付款人的公式计算(实际上,保险公司,这对于已经进入默认的抵押贷款)必须在开具发票根据其他规则,每defauted抵押规定顺序。

所有这一切都在做的意见,用短(100行左右)存储过程,基本上做了什么,我已经概述上面:使用通过这些规则有序发票的开票视图,用于支付(在视图),计算哪些额外支付什么日期到保险公司发票。存储过程然后当前日期刚刚生成的发票(其当前日期可以被设置,再次使用的图,以任何日期用于测试目的)。

(具有讽刺意味的是,我已经采取onteh承诺作业我得到写C ++;唯一的C ++我写使用的Oracle和SybaseÇ的API将数据从Oracle系统转移到Sybase之一。)

其他提示

此应该这样做。我声明了一个局部变量,但你可以做,从一个存储过程的参数。我还添加了一个INVOICE_ID表中唯一标识发票,因为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

除非这是一个一次性的工作......

听起来好像这是楼内设有商务逻辑和在应用程序的业务层所属。

您必须使用一对夫妇光标和两个嵌套的循环。 (这可能是有点慢)

一读取所有付款 - 我假定客户,金额

然后,对于每个客户创建另一个光标用于打开的项目。

在第一循环将读付款,直到完成

在这个循环中打开一个新的光标,为客户的最旧第一排序开放的项目。

通过每个打开的项目环路和像你描述应用该付款

然后得到下一笔款项。

重复,直到没有更多的付款。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top