大型.NET ERP系統的20條資料庫設計規範
資料庫設計規範是個技術含量相對低的話題,只需要對標準和規範的堅持即可做到。當系統越來越龐大,嚴格控制資料庫的設計人員,並且有一份規範書供執行參考。在程式框架中,也有一份強制性的約定,當不遵守規範時報錯誤。
以下20個條款是我從一個超過1000個資料庫表的大型ERP系統中提煉出來的設計約定,供參考。
1 所有的表的第一個欄位是記錄編號Recnum,用於資料維護
[Recnum] [decimal] (8, 0) NOT NULL IDENTITY(1, 1)
在進行資料維護的時候,我們可以直接這樣寫:
UPDATE Company SET Code='FLEX' WHERE Recnum=23
2 每個表增加4個必備欄位,用於記錄該筆資料的建立時間,建立人,最後修改人,最後修改時間
[CreatedDate] [datetime] NULL, [CreatedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL, [RevisedDate] [datetime] NULL, [RevisedBy] [nvarchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
框架程式中會強制讀取這幾個欄位,預設寫入值。
3 主從表的主外來鍵設計
主表用參考編號RefNo作為主鍵,從表用RefNo,EntryNo作為主鍵。RefNo是字串型別,可用於單據編碼功能中自動填寫單據流水號,從表的EntryNo是行號,LineNo是SQL Server 的關鍵字,所以用EntryNo作為行號。
如果是三層表,則第三層表的主鍵依次是RefNo,EntryNo,DetailEntryNo,第三個主鍵用於自動增長行號。
4 設計單據狀態欄位
欄位 | 含義 |
Posted | 過帳,已確認 |
Closed | 已完成 |
Cancelled | 已取消 |
Approved | 已批核 |
Issued | 已發料 |
Finished | 已完成 |
Suspended | 已取消 |
5 欄位含義相近,把相同的單詞調成字首。
比如工作單中的成本核算,人工成本,機器成本,能源成本,用英文表示為LaborCost,MachineCost,EnergyCost
但是為了方便規組,我們把Cost調到欄位的前面,於是上面三個欄位命名為CostLabor,CostMachine,CostEnergy。
可讀性後者要比前者好一點,Visual Studio或SQL Prompt智慧感知也可幫助提高欄位輸入的準確率。
6 單據引用鍵命名 SourceRefNo SourceEntryNo
銷售送貨Shipment會引用到是送哪張銷售單據的,可以新增如下引用鍵SourceRefNo,SourceEntryNo,表示送貨單引用的銷售單的參考編號和行號。Source開頭的欄位一般用於單據引用關聯。
7 資料字典鍵設計
比如員工主檔介面的員工性別Gender,我的方法是在原始碼中用列舉定義。性別列舉定義如下:
public enum Gender { [StringValue("M")] [DisplayText("Male")] Male, [StringValue("F")] [DisplayText("Female")] Female }
在程式碼中呼叫列舉的通用方法,讀取列舉的StringValue寫入到資料庫中,讀取列舉的DisplayText顯示在介面中。
經過這一層設計,資料庫中有關字典方面的設計就規範起來了,避免了資料字典的項的增減給系統帶來的問題。
8 數值型別欄位長度設計
Price/Qty 數量/單價 6個小數位 nnnnnnnnnn.nnnnnn 格式 (10.6)
Amount 金額 2個小數位 nnnnnnnnnnnn.nn 格式(12.2)
Total Amt 總金額 2個小數位 nnnnnnnnnnnnnn.nn 格式(14.2)
參考編號預設16個字元長度,不夠用的情況下增加到30個字元,再不夠用增加到60個字元。這樣可以保證每張單據的第一個參考編號輸入控制元件看起來都是一樣長度。
除非特別需求,一般而言,介面中控制元件的長度取自對映的資料庫中欄位的定義長度。
9 每個單據表頭和明細各增加10個自定義欄位,基礎資料表增加20個自定義欄位
參考供應商主檔的自定義欄位,自定義欄位的名稱統一用UserDefinedField。
ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_1] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_2] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_3] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_4] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_5] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_6] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_7] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_8] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_9] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_10] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_11] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_12] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_13] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_14] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_15] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_16] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_17] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_18] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_19] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ALTER TABLE Vendor ADD COLUMN [USER_DEFINED_FIELD_20] nvarchar(100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
10 多貨幣(本位幣)轉換欄位的設計
金額或單價預設是以日記帳中的貨幣為記錄,當預設貨幣與本位幣不同時需要同時記錄下本位幣的值。
銷售單銷售金額 SalesAmount或SalesAmt,本位幣欄位定義為SalesAmountLocal或SalesAmtLocal
通常是在原來的欄位後面加Local表示本位幣的值。
11 各種日期欄位的設計
欄位名稱 | 含義 |
TranDate | 日期帳日期 Tran是Transaction的簡寫 |
PostedDate | 過帳日期 |
ClosedDate | 完成日期 |
InvoiceDate | 開發票日期 |
DueDate | 截止日期 |
ScheduleDate | 計劃日期,這個欄位用在不同的單據含義不同。比如銷售單是指送貨日期,採購單是指收貨日期。 |
OrderDate | 訂單日期 |
PayDate | 付款日期 |
CreatedDate | 建立日期 |
RevisedDate | 修改日期 |
SettleDate | 付款日期 |
IssueDate | 發出日期 |
ReceiptDate | 收貨日期 |
ExpireDate | 過期時間 |
12 財務有關的單據包含三個標準欄位
FiscalYear 財年,PeriodNo 會計期間,Period 前面二個的組合。以國外的財年為例子,FiscalYear是2015,PeriodNo是4,Period是2015/04。
歐美會計期間是從每年的4月份開始,需要注意的是會計期間與時間沒有必然的聯絡,看到會計期間是2015/04,不一定是表示2015的4月份,它只是說這是2015財年的第四期,具體在哪個時間段需要看會計期間定義。
13 單據自動生成 DirectEntry
有些單據是由其它單據生成過來的,邏輯上應該不支援編輯。比如銷售送貨Shipment單會產生出倉單,出倉單應該不支援編輯,只能做過帳扣減庫存操作。這時需要DirectEntry標準欄位來表示。當手工建立一張出倉單時,將DirectEntry設為true,表示可編輯單據中的欄位值,當由其它單據傳遞產生過來產生的出倉單,將DirectEntry設為false,表示不能編輯此單據。這種情況還發生在業務單據產生記帳憑證(Voucher)的功能中,如果可以修改由原始單據傳遞過來的數量金額等欄位,則會導致與源單不匹配,給系統對帳產生困擾。
14 百分比值欄位的設計
Percentage百分比值,用於折扣率,損耗率等相關比率設定的地方。推薦用數值型別表示,用指令碼表示是
[ScrapRate] [decimal] (5, 2) NULL
預留兩位小數,整數部分支援1-999三位數。常常是整數部分2位就可以,用3位也是為了支援一些特殊行業(物料損耗率超過100)的要求。
15 日誌表記錄編號LogNo欄位設計
LogNo欄位的設計有些巧妙,以出倉單為例子,一張出倉單有5行物料明細,每一行物料出倉都會扣減庫存,再寫物料進出日記帳,因為這五行物料出倉來自同一個出倉單,於是將這五行物料的日記帳中的LogNo都設為同一個值。於在查詢資料時,以這個欄位分組即可看到哪些物料是在同一個時間點上出倉的,對快速查詢有很重要的作用。
16 基礎資料表增加名稱,名稱長寫,代用名稱三個欄位
比如供應商Vendor表,給它加以下三個欄位:
Description 供應商名稱,比如微軟公司。
ExtDescription 供應商名稱長寫,比如電氣行業的南網的全名是南方國家電網有限公司。
AltDescription 供應商名稱替代名稱,用在報表或是其它單據引用中。比如採購單中的供應商是用微軟,還是用代用名稱Microsoft,由引數(是否用代用名稱)控制。
17 檔案類表增加MD5 Hash欄位
比如產品資料管理系統要讀取圖紙,單據功能中增加的附件檔案,這類涉及檔案讀寫引用的地方,考慮存放檔案的MD5雜湊值。檔案的MD5相當於檔案的唯一識別身份,在網上下載檔案時,網站常常會放出檔案的MD5值,以方便對比核對。當下載到本機的檔案的MD5值與網站上給出的值不一致時,有可能這個檔案被第三方程式修改過,不可信任。
18 資料表的主鍵用字串而不是數字
比如銷售單中的貨幣欄位,是存放貨幣表的貨幣字串值RMB/HKD/USD,還是存放貨幣表的數字鍵,1/2/3。
存放前者對於報表製作相對容易,但是修改起來相對麻煩。存放後者對修改資料容易,但對報表類或查詢類操作都需要增加一個左右連線來看數字代表的貨幣。金蝶使用的是後者,它的BOS系統也不允許資料表之間有直接的關聯,而是間接通過Id值來關聯表。
在我看到的系統中,只有一個會計期間功能(財年Fiscal Year)用到數字值作主鍵,其餘的單據全部是字串做主鍵。
19 使用約定俗成的簡寫
模組Module 簡寫
簡寫 | 全名 |
SL | Sales 銷售 |
PU | Purchasing 採購 |
IC | Inventory 倉庫 |
AR | Account Receivable 應收 |
AP | Account Payable 應付 |
GL | General Ledger 總帳 |
PR | Production 生產 |
名稱Name 簡寫
簡寫 | 全名 |
Uom | Unit of Measure 單位 |
Ccy | Currency 貨幣 |
Amt | Amount 金額 |
Qty | Quantity 數量 |
Qty Per | Quantity Per 用量 |
Std Output | Standard Output 標準產量 |
ETA | Estimated Time of Arrival 預定到達時間 |
ETD | Estimated Time of Departure 預定出發時間 |
COD | Cash On Delivery 貨到付款 |
SO | Sales Order 銷售單 |
PO | Purchase Order 採購單 |
20 庫存單據數量狀態
Qty On Hand 在手量
Qty Available 可用量
Qty On Inspect 在驗數量
Qty On Commited 提交數量
Qty Reserved 預留數量
以上每個欄位都有標準和行業約定的含義,不可隨意修改取數方法。
相關文章
- 解析大型.NET ERP系統:20條資料庫設計規範資料庫
- 資料庫設計規範資料庫
- MySQL 規範 (資料庫表設計規範)MySql資料庫
- MongoDB資料庫的設計規範MongoDB資料庫
- MySQL資料庫規範 (設計規範+開發規範+操作規範)MySql資料庫
- MySQL資料庫設計規範MySql資料庫
- 解析大型.NET ERP系統:十三種介面設計模式設計模式
- 解析大型.NET ERP系統 設計異常處理模組
- 解析大型.NET ERP系統:高質量.NET程式碼設計模式設計模式
- MySQL 資料庫規範--設計篇MySql資料庫
- MySQL之規範資料庫設計MySql資料庫
- SQL Server 資料庫設計規範SQLServer資料庫
- MySQL-11.資料庫的設計規範MySql資料庫
- 解析大型.NET ERP系統:單據標準功能程式設計程式設計
- 大話資料庫程式設計規範資料庫程式設計
- 八、資料庫的歸約,三大正規化(規範資料庫設計)資料庫
- 資料庫設計規範化的 5 個要求資料庫
- 超大型Oracle資料庫應用系統的設計方法Oracle資料庫
- Postgresql 31條資料庫開發規範SQL資料庫
- MySQL資料庫設計與開發規範MySql資料庫
- MySQL資料庫基本設計規範總結MySql資料庫
- 《MySQL 進階篇》十六:資料庫的設計規範MySql資料庫
- 簡化服裝ERP系統的規範流程和規範功用
- 常見的資料設計規範
- ERP 資料庫設計資料庫
- MYSQL資料庫欄位命名及設計規範MySql資料庫
- 超大型Oracle資料庫應用系統的設計方法(下)UVOracle資料庫
- 解析大型.NET ERP系統:程式碼異味
- 併發程式設計的12條規範程式設計
- 必看的資料庫規範資料庫
- MySQL資料庫設計規範和優化建議MySql資料庫優化
- 資料庫系統原理-關聯式資料庫的規範化理論總結資料庫
- 資料庫:系統設計的核心資料庫
- ASP.NET程式設計中的9條程式碼編寫規範ASP.NET程式設計
- 資料庫設計中的反規範技術探討(轉)資料庫
- mysql資料庫規範MySql資料庫
- 資料庫命令規範資料庫
- 資料庫系統操作規範及SQL書寫建議資料庫SQL