Sql server动态序列

时间:2014-12-30 13:40:29

标签: sql sql-server sql-server-2012

这是一个理论情景,

假设我有一个客户表和一个发票表。 1个客户可以有很多发票。

现在我希望每张发票都有一个该客户独有的发票号

ClientId InvoiceNo
1        IN0001
2        IN0001
2        IN0002
2        IN0003
3        IN0001

目前我通过查看最大值等来控制我的应用程序,但这显然不是一个很好的解决方案。我更愿意让我的数据库为我这样做,因为它应该消除为单个客户创建重复的发票号码的风险(竞争条件?)

我一直在阅读Sql Server 2012的SEQUENCE,这听起来很棒,但问题是我仍然需要每个客户端单独的序列

即。

CREATE SEQUENCE InvoiceNum_Client1.....
CREATE SEQUENCE InvoiceNum_Client2.....
CREATE SEQUENCE InvoiceNum_Client3.....

但每次创建新客户端时,从我的应用程序中进行db meta更改都会让人觉得非常脏。此外,我的触发器必须做这样的事情(我甚至不知道该怎么做)

NEXT VALUE FOR InvoiceNum_Client + @ClientId

所以我的下一个想法是有一个“序列”表,即

ClientID   INSequenceNumber
1           1
2           3
3           3

在我的触发器中获取给定客户端的InSequenceNumber,使用它来生成invoiceNumber,然后更新序列表,为同一客户端递增InSequenceNumber 1。它应该具有相同的效果,但我只是不确定交易和范围等的内部运作方式

所以我的问题是

  1. 我的自卷序列方法有什么大的缺点吗?
  2. 我可能会忽略另一种解决方案吗?
  3. 谢谢!

2 个答案:

答案 0 :(得分:1)

是否有特定原因要求发票编号仅对每个客户而言是唯一的?在大多数ERP系统中,发票编号通常是全球唯一的,使实施更加容易。无论如何,你应该有一个包含主键的Invoice表(你不应该使用复合主键 - 这只是简单的坏数据建模)。

这给我们留下了一个场景,您可能根本不需要在数据库中存储“per-client-invoice-number”。假设您有一个名为“Invoices”的表,其中包含以下数据:

Id   | ClientId
---------------
  1  |        1
  2  |        1
  3  |        2
  4  |        1
  5  |        3
  6  |        2

此处,Id是发票表的主键,而ClientId是外键。像这样的查询:

SELECT 
    ClientId,
    'IN' + RIGHT('0000' + 
             CONVERT(VARCHAR, ROW_NUMBER() OVER (PARTITION BY ClientId 
                                                 ORDER BY Id)) AS InvoiceNo,
    Id
FROM Invoices
ORDER BY ClientId, InvoiceNo

会回来:

ClientId | InvoiceNo | Id
---------------------------
      1  |    IN0001 |  1
      1  |    IN0002 |  2
      1  |    IN0003 |  4
      2  |    IN0001 |  3
      2  |    IN0002 |  6
      3  |    IN0001 |  5

答案 1 :(得分:0)

为什么客户必须拥有自己的序列?有一个全局序列号。然后,如果要按顺序获取客户端序列,请使用row_number()

select i.*, row_number() over (partition by clientid order by invoiceno) as ClientInvoiceSequence
from invoices;

注意:您可能希望order by位于其他字段,例如日期。

如果您开始将此信息存储在数据库中,您将需要进行大量的簿记和谨慎的事务管理:

  • “同时”输入两张发票时会发生什么?
  • 删除发票后会发生什么?
  • 如果修改发票可能会改变顺序,会发生什么?

最好使用标识列并在需要时计算序列。