SQL Server - 前缀和零填充ID列

时间:2017-07-02 06:27:03

标签: sql sql-server database-design sql-server-2014

为了快点,这是我的问题,我一直在尝试搜索StackOverflow的答案,但我找不到满意的答案。

我有一个包含列(简化)的InvoiceHeader表:

InvoiceID   : Int - PK Identity(1,1)
InvoiceDate : date
CustomerID  : Int - FK to Customer table

等等...

我会经常向用户显示有关发票的信息。 当我向用户显示发票号时,我需要添加前缀和零填充 InvoiceID。

例如:

InvoiceID : 1 
Invoice Number : INV0000001

我的问题是,我应该在InvoiceHeader表格中设置全新 PERSISTED COMPUTED列,以保存格式化的发票号码,如下所示:

InvoiceNumber AS 'INV' + RIGHT('000000'+cast(InvoiceID as varchar(7)),7)

或者我应该选择InvoiceID并在运行时从我的应用程序处理INV0000001

我的困境:

  • 如果我添加一个新的PERSISTED COMPUTED列(即InvoiceNumber),那么我可以在InvoiceNumber上创建一个非聚簇索引,当WHERE子句中有InvoiceNumber查询时,这将有所帮助。但是这仍然需要覆盖索引或包含索引以获得其他列的值。另外一个好处是我不必格式化#34;每当我需要显示它时,它就会成为INV0000001。
  • 如果我从我的应用程序将SELECT QUERY的InvoiceID格式化为INV0000001,那将会太多" chore",每次我想要显示InvoiceNumber我必须格式化它。但是我不需要另一个列,它与InvoiceID基本上具有相同的值,带有一些前缀和零填充。
  • 用户将使用发票编号进行搜索,例如:找到一个编号为' 1234' +'%'的发票。如果对InvoiceID(整数列)执行此操作,它将进行IMPLICIT转换,它会使查询更慢吗? PK索引是否仍会被查询计划使用?

编辑: 考虑到我每次需要时都需要手动格式化发票编号的许多地方(如果我不使用计算列),我现在几乎肯定会选择 Esperento57' s解决方案

制作2个新专栏:

InvoiceID      : int identity (PK)
Prefix         : char(3) --> INV, etc
InvoiceNumber  : Prefix + RIGHT('000000'+cast(InvoiceID as varchar(7)),7)

但我不会让PK包含前缀,因为InvoiceID是identity所以它本身就是唯一的。

我还在考虑@Matt关于分离关注点的观点,因为它有意义。

4 个答案:

答案 0 :(得分:1)

您应该将其作为数值保存在数据库中并对其进行格式化,这将阻止您不必要地存储没有价值的数据并提高查询性能。您可以在应用程序中以较低级别应用格式,如果这会减少您需要格式化的位置数量,但根据应用程序的复杂程度,您不太可能需要多次编写此格式化逻辑。

修改

其他答案中有一些有效点,例如:关于缺失数字的观点可能对你很重要,也可能不重要 - 只有你知道这是否相关。

将来改变前缀的问题我要警惕,除非你现在知道这是一个具体的要求。无论是将其存储在数据库中,还是在视图中或在UI /业务层中生成,都可以通过多种方式来改进前缀的更改。这是我向KISSYAGNI建议的其中一项内容!

NB。 Martin Fowler在上面的文章中提出了一个非常好的观点,即关于构建推定功能和构建可扩展软件之间的区别。这是在考虑围绕这些类型问题进行设计时始终使用的重要措施 - 尽可能确保您拥有扩展点,但只能实现您所需要的功能。

答案 1 :(得分:1)

我的专栏建议:

  • InvoiceID:整数非空,带有自动增量(不需要序列,SQL Server可以完成工作)

  • 前缀:varchar(10)在PREFIXTABLE上不为FK

  • InvoiceID和Prefix是主键

  • InvoiceNumber:计算并保留列=前缀+右('0000000'+ InvoiceID,7)

  • 在InvoiceNumber

  • 上添加索引

根据我的提议,你可以:

  1. 必要时更改前缀
  2. 前缀
  3. 上有完整性
  4. 您的complet密钥具有完整性,并保留真正的主键
  5. 您无需重新计算完整的密钥
  6. 如果是数据恢复,您可以将序列跳转到您的键或只是选择另一个前缀
  7. 您可以在PREFIX表中添加说明以解释您的前缀(例如,对于futur developper)

答案 2 :(得分:0)

我认为您应该从用户看到的字符串中分离内部ID,它是主键并用于标识记录。

最终用户永远不应该看到IDENTITY生成的ID,因为很容易出现差距。

因此,我有两个常规列:int InvoiceIDchar(10) InvoiceNumber。是的,会有一个单独的方法来生成下一个发票编号。在SQL Server 2014中,我使用带有NO CACHE选项的SEQUENCE对象。

当您将内部ID与用户可见的发票编号分开时,您可以在以后轻松更改这些编号的格式。例如,在两年内,财务部门可能会决定引入另一个前缀ABC000001。显然,所有现有的历史发票都应保留其编号。使用单独的发票编号列,没有问题。使用计算列,您将遇到问题。

答案 3 :(得分:0)

如果这是计算invoicenumber的公式,

InvoiceNumber  : Prefix + RIGHT('000000'+cast(InvoiceID as varchar(7)),7)

这里的invoicenumber之间的差距并不重要。

然后我只保留InVoiceID。显示我将以低级别或proc本身的方式格式化invoicenumber。 当用户搜索发票号时,我删除前缀并将其转换为int变量。

然后我会搜索invoiceID列。

但是如果前缀可能会改变,那么在invoicenumber之间就不应该有GAP,

i)在同一个表中保留前缀是个坏主意。

ii)另外,对于invoicenumber的计算也会改变,因为你必须保持连续性。

  

但是我不会让PK包括Prefix因为InvoiceID是身份所以   它本身就是独一无二的。

它取决于。根据我的说法,前缀也是不可能的。但InvoiceID可以是PK + CI或仅PK或仅限身份或仅CI。

你要检查每个选项。