发票和付款的架构设计 - 比M:M关系更好的模型?

时间:2012-01-31 19:36:29

标签: sql sql-server-2008 relational-database database-schema

现有架构中的发票和项目之间存在1:1的关系。我正在修改它以允许一个项目有很多发票,但我还需要跟踪付款。

目前,单笔付款涉及1张(或更多张)发票(实际上是发票批次)。理想情况下,可以跟踪每张发票的多笔付款。为此,我认为发票和付款之间需要有M:M关系。

因此,一旦存储了数据,如何确定单个项目需要支付多少钱?如何确定单个客户欠多少钱?我想不出如何正确分组和总结。

到目前为止,我已经提出了几种方法,方法1-3在不同程度上基于下面代码中的表/值。我刚才提出方法4,目前看起来似乎是一个可行的选择,但它不允许你确定在所有场景中对单个项目的欠款。

  1. 创建3个不同的查询,这些查询依赖于关系类型(#payinv表中的relType字段),其中2个我知道如何制作。例如,relType = '1:M',我可以在第一方进行分组,并将多方面相加;反之亦然relType = 'M:1'。但是当relType = 'M:M我不知所措时。

  2. 在每个发票/付款中加入ProjectIDBillToPartyID属性。我可以汇总并比较单个项目的所有发票和付款,但是当付款涵盖多个发票时,似乎已经为该项目支付了太多。如果我拉出BillToParty所欠的东西,我就无法确定他们还欠钱的项目。

  3. 我可以尝试将结算和付款值存储在联结表中。例如,在输入付款时,用户将付款应用于发票。系统将确定在用户尝试以3个步骤创建的记录中输入的值。 #1它将通过汇总已在联结表中的当前发票金额计算剩余余额,然后从原始发票金额中减去该值。 #2它将以类似的方式计算可用于支付的剩余资金。 #3它会将余额与可用资金进行比较,并将结算表中的付款和发票两种金额中的较小者输入。我看到三种可能性: a)如果发票的余额为0,则付款和发票均已关闭以供进一步使用。 b)如果发票的余额少于付款,则发票将关闭,付款仍可用于其他发票。 c)如果发票的剩余余额大于付款,付款将被关闭,发票仍然开放。除了复杂性,我没有看到这个想法的问题......

  4. 我可以将BillToParty分配给发票批次,发票批次将是发票和付款的父级。如果客户支付不足,我们可以计算剩余余额并生成新的“发票”(原始意义上的不是发票,可能不想存储这个???)。如果他们多付,我们必须发放信用,因为我们无法将付款应用于另一批。

        CREATE TABLE #inv
            (
            invID int NOT NULL,
            invAMT int NULL
            )  ON [PRIMARY]
        GO
        ALTER TABLE #inv ADD CONSTRAINT
            PK_inv PRIMARY KEY CLUSTERED 
            (
            invID
            )
        CREATE TABLE #pay
            (
            payID varchar(50) NOT NULL,
            payAMT int NULL
            )  ON [PRIMARY]
        GO
        ALTER TABLE #pay ADD CONSTRAINT
            PK_pay PRIMARY KEY CLUSTERED 
            (
            payID
            ) 
        CREATE TABLE #payinv
            (
            payID varchar(50) NOT NULL,
            invID int NOT NULL,
            relType varchar(50) not null
            )  ON [PRIMARY]
        GO
        ALTER TABLE #payinv ADD CONSTRAINT
            PK_payinv PRIMARY KEY CLUSTERED 
            (
            payID,
            invID
            )
        INSERT INTO #inv (invID, invAMT)
        select 1,110
        union
        select 2,400
        union
        select 3,600
        union
        select 4,100000
        union
        select 5,10000
        union
        select 6,1000000;
    
        INSERT INTO #pay (payID,payAMT)
        select 'a',10
        union
        select 'b',100
        union
        select 'c',1000
        union
        select 'd',10000
        union
        select 'e',100000
        union
        select 'f',1000000;
    
        INSERT INTO #payinv(payID,invID,relType)
        select 'a',1,'1:M'
        union
        select 'b',1,'1:M'
        union
        select 'c',2,'M:1'
        union
        select 'c',3,'M:1'
        union
        select 'd',4,'M:M'
        union
        select 'e',4,'M:M'
        union
        select 'e',5,'M:M'
        union
        select 'f',6,'1:1';
    
        select #inv.invAMT, #inv.invID, #pay.payID, #pay.payAMT, #payinv.relType
        from #inv inner join #payinv on #inv.invID = #payinv.invID inner join #pay on #payinv.payID = #pay.payID
    

1 个答案:

答案 0 :(得分:0)

作为PK的一部分,您需要在项目,发票和付款表中使用billToPartyID(或customerID,我假设它们是相同的,或者它们之间存在1> 1关系)。那么你的关系是:

“客户/ billToParty可以有很多项目,可以有很多发票。客户/ billToParty的付款可以应用于许多客户的发票,必须指定。”

然后,应该更容易按客户ID跟踪总计,包括付款和未结清的发票金额。