自增長字段值的連續遞增實現
一.背景
在上一篇《數據庫操作類SqlHelper》博文的最後,提到了一個實踐運用中遇到的問題,就是數據庫表中的自增長字段的賦值不受人為控制。比如數據庫有一個tb_Department表,DeptNO字段為自增長主鍵。
現在插入一行數據
啊!DeptNO字段怎麽就是22了呢,不應該是從4開始嗎?
原因:這個表之前進行過很多插入操作,數據庫針對自增長字段的每次插入都會自動+1,後來刪除了一部分行數據,然後重新插入的時候,數據庫不會依據表中缺失的字段值進行賦值,而是在原先的基礎上繼續+1賦值。
結果:在新插入的“哈哈系”數據行之前,其實數據庫已經向表裏插入過21次了,只是DeptNO字段值大於
期望:
- 在插入新數據的時候,針對自增長字段可以人為控制;
- 實際運用中,其實用戶並不知道數據表中自增長字段缺失的是哪些值,程序需要自動提供缺失或者缺省值。
二.設計
1.在插入新數據的時候,針對自增長字段可以人為控制
數據庫中針對自增長字段在插入時,不可以指定顯式值的。
insert into tb_Department(DeptNO,DeptName) values(4,N‘嘿嘿系‘)
這樣插入數據會報錯的,提示你“當Identity_Insert設置為off時,不能為表’tb_Department’中的標識列插入顯式值
set identity_insert tb_Department on insert into tb_Department(DeptNO,DeptName) values(4,N‘嘿嘿系‘) set identity_insert tb_Department off
執行看看能不能插入,哇哦,成功了,棒棒噠。
2.實際運用中,用戶並不知道數據表中自增長字段未使用有哪些值,程序需要自動提供缺失或者缺省值
自增長字段的值分為缺失值和缺省值(這個術語是我自己定的,為了方便描述)
缺失值:比如數據表中自增長字段的值為(1,2,3,5),則缺失值為4。要想讓程序自動檢索到缺失值,需要對數據表進行全面掃描,逐行判斷自增長字段的值是否連續遞增,只要檢索到不連續的值就將對應序列的值返回,並顯示在窗體上,無需用戶自己輸入。
缺省值:比如數據表中自增長字段的值為(1,2,3,4),則缺省值為5。假設原先有10行數據,然後將大於4的行刪除後,自增長字段本身還是連續遞增的,只需要找到缺省值,返回給用戶。
利用SQL腳本創建存儲過程實現:(註意:該實現返回當前自增長字段中第一個缺失值/缺省值,只適用於每次插入一行數據的情況)
--創建一個存儲過程用於自動提取自增長字段的第一個缺失值和缺省值 create procedure NumOfDeptNOForInsert @temp int output --定義一個輸出參數,用於返回缺失值/缺省值 as declare @Count int --定義一個當前表中的行數 select @Count=COUNT(1) from tb_Department --給變量@Count賦值 declare @I int, @IsOK bit = 0,@num int = 1 --定義一個用於循環的@I變量,一個用於判斷是缺失值還是缺省值的變量@IsOK,一個記錄缺省值的變量@num set @I = 1; --變量@I賦值為1 while(@I <= @Count) --開始循環掃描行數據 begin select @temp=DeptNO from tb_Department where DeptNO=@I --檢索DeptNO值=@I值的行數據 if(@temp != @I) --判斷@I值與DeptNO值是否比對不成功 begin set @temp = @I --將@I值賦值給@temp set @IsOK = 0 --標記為缺失值 break --退出循環 end else --判斷@I值與DeptNO值是否比對成功 begin set @I = @I +1 --@I+1 set @num = @I --將@I賦值給@num set @IsOK = 1 --標記為缺省值 end end if(@IsOK =0) --判斷是缺失值還是缺省值,如果是缺失值 begin select @temp --直接返回@temp end else --如果是缺省值 begin set @temp = @num --將@num賦值給@temp select @temp --再返回@temp end
自增長字段的連續遞增插入的存儲過程設計好後,首先在SQL Server中檢驗一下。
declare @temp int --定義輸出參數 exec dbo.NumOfDeptNOForInsert @temp --調用儲存過程 print @temp --打印輸出參數
- 缺失值的檢驗:
調用存儲過程看看缺失的第一個值是不是5,結果跟預期一樣。
- 缺省值的檢驗:
調用存儲過程,找到的第一個缺省值為7,結果跟預期的一樣。
三.實踐
前面的分析設計做好後,當然就是運用於實踐了,主要是編寫獲取自增長字段的缺失值/缺省值的方法:
/// <summary> /// 獲取自增長字段的第一個缺失值或者缺省值 /// </summary> /// <returns>缺失值/缺省值</returns> private int GetDeptNO() { string cmdText = @"NumOfDeptNOForInsert"; SqlParameter[] parameters = { new SqlParameter("@temp",SqlDbType.Int) }; parameters[0].Direction = ParameterDirection.Output; int deptNO = (int)SqlHelper.ExecuteScalar(SqlHelper.ConnString, CommandType.StoredProcedure, cmdText,parameters); return deptNO; }
程序整體的UI設計和編碼在博文《數據庫操作類SqlHelper》中都已經講述,這裏就不在反復講了。相對於之前來說,需要更改代碼的地方為“增加”按鈕的點擊處理程序和InsertData()方法:
private void tsbInsert_Click(object sender, EventArgs e) { cmdType = CmdType.Insert; //將gbDept控件設置可用,textbox控件設為可用,並將Text屬性清空 this.gbDept.Enabled = true; this.txtDeptName.Enabled = true; this.txtDeptName.Text = string.Empty; //顯示即將插入的DeptNO值 this.lbDeptNO.Text = GetDeptNO().ToString(); } /// <summary> /// 插入數據 /// </summary> private void InsertData() { //判斷系部名稱是否為空 if (string.IsNullOrEmpty(this.txtDeptName.Text.Trim())) { MessageBox.Show("系部名稱不能為空!"); return; } //定義插入數據的SQL腳本,其中set identity_insert tb_Department on/off主要是為了能讓自增長主鍵連續有序地插入 string cmdText = @"set identity_insert tb_Department on insert into tb_Department(DeptNO,DeptName) values(@DeptNO,@DeptName) set identity_insert tb_Department off"; ////定義插入數據的Sql腳本 //string cmdText = @"insert into tb_Department(DeptName) values(@DeptName)"; //SQL腳本參數設置 SqlParameter[] parameters = { new SqlParameter("@DeptNO",(object)this.lbDeptNO.Text), new SqlParameter("@DeptName",(object)this.txtDeptName.Text.Trim()) }; //執行插入,並返回受影響的行數 int rows = SqlHelper.ExecuteNonQuery(SqlHelper.ConnString, CommandType.Text, cmdText, parameters); //判斷是否插入成功,並提示 if (rows > 0) { //更新datagridview控件的數據 LoadData(); //顯示即將插入的DeptNO值 this.lbDeptNO.Text = GetDeptNO().ToString(); //將系部名稱設為空 this.txtDeptName.Text = string.Empty; MessageBox.Show("插入成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("插入失敗!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } private void btnOK_Click(object sender, EventArgs e) { //執行增刪改操作 switch (cmdType) { case CmdType.Insert: InsertData(); break; case CmdType.Delete: DeleteData(); break; case CmdType.Update: UpdateData(); break; } }
四.結果
UI和編碼完成後,調試程序是很關鍵的,能從調試的過程中重現整個功能的思路,也能找到一些問題所在,修復bug,然後重編碼。廢話不多說看結果吧:
1.缺失值:
假設一開始的tb_Department表如下圖所示,理論上缺失的值為(4,5,7),現在往表裏插入新值,看看結果如何。點擊“增加”按鈕,窗體下方系部編號自動出現第一個缺失值4,系部名稱我們設置為“嘟嘟系”,提交添加成功後,系部編號會自動顯示下一個缺失值5。為了後面的缺省值的結果,我們再增加缺失值(5,7)兩行數據,使DeptNO字段連續遞增。
2.缺省值:
當DeptNO字段連續遞增時,如下圖所示,點擊“增減”按鈕,窗體下方的系部編號成功地提取到第一個缺省值9,系部名稱輸入“物理系”,提交增加成功後,系部編號會自動顯示下一個缺省值10。
調試結果顯示我們提出的需求已經得到解決。
一.總結
本文主要針對數據表中自增長字段的插入問題進行講解,不管表中的數據增刪過多少次,程序總是能提供自增長字段的缺失值或者缺省值用於新數據行的插入,從而實現插入自增長字段值的連續遞增特性。
自增長字段值的連續遞增實現