用一句SQL解決SQL中斷號問題
名詞解釋
斷號:比如,連續生成的編號,由于某種操作(通常為刪除)后,產生不連續的編號,我們將這種不連續的編號稱為斷號。
例如,數據庫中有一個字段叫合同編號,正常格式為201106_011(表示2011年6月的第11個合同),那么它前面的一個合同編號應該為201106_10,后面的一個應該為201106_12,當我們刪除了合同201106_011,就會出現201106_010后面直接是201106_012,這種情況下叫做斷號。
傳統系統中,像這種斷號的情況很常見,比如數據庫中的列為遞增類型,當刪除某行后,就會出現斷號,而經常有客戶提出需求,不希望出現斷號的情況。解決方案通常就是,如果刪除了某行數據,那么下次新增時,應該將斷號補齊。
問題很簡單,解決方法也很簡單:
寫一個C#方法,用來獲取下一條記錄的編號:
- public static int GetNextNumber(int[] iNumList)
- {
- int iTempStr = iNumList[0]; //用一個臨時變量保存上一條記錄的編號
- for (var i = 0; i < iNumList.Length - 1; i++)
- {
- if (i == 0)
- {
- iTempStr = iNumList[i];
- }
- //如果出現斷號,則補齊斷號
- if ((iNumList[i] - iTempStr) > 1)
- {
- return iTempStr + 1;
- }
- else
- {
- iTempStr = iNumList[i];
- }
- continue;
- }
- return iNumList[iNumList.Length - 1] + 1;
- }
當然,這段代碼也可以簡寫為以下形式:
- public static int GetNextNumber3(int[] iNumList)
- {
- for (int i = 0, j = 1; j < iNumList.Length - 1; i++, j++)
- {
- //如果出現斷號,則補齊斷號
- if ((iNumList[j] - iNumList[i]) > 1)
- {
- return iNumList[i] + 1;
- }
- }
- return iNumList[iNumList.Length - 1] + 1;
- }
測試代碼如下:
- static void Main(string[] args)
- {
- int[] iNums = { 1, 2, 4, 5, 6, 9, 10 }; //刪除了數組中的3,7,8,即3,7,8為斷號,下次新增時,希望產生的斷號為3
- System.Console.WriteLine(BreakNumber.GetNextNumber3(iNums));
- System.Console.WriteLine(BreakNumber.GetNextNumber(iNums));
- }
運行結果如下:
前幾天再次接觸到這個問題,由于特殊的場景,再用C#反而會增加開發難度,如果想法通過SQL來解決問題:
建表及制造數據SQL:
- CREATE TABLE testTable
- (
- Code int primary key
- )
- INSERT INTO testTable(Code) VALUES (1)
- INSERT INTO testTable(Code) VALUES (2)
- INSERT INTO testTable(Code) VALUES (3)
- INSERT INTO testTable(Code) VALUES (4)
- INSERT INTO testTable(Code) VALUES (5)
- INSERT INTO testTable(Code) VALUES (6)
- INSERT INTO testTable(Code) VALUES (7)
- INSERT INTO testTable(Code) VALUES (8)
- INSERT INTO testTable(Code) VALUES (9)
- INSERT INTO testTable(Code) VALUES (10)
然后再同樣刪除第3、7、8行的數據,使這三行產生斷號:
- DELETE FROM testTable WHERE Code in (3,7,8)
分析:要產生連號,即是要讓Code這一列上連續的,也就是說每每兩行之間的Code相差為1
由于Code是從1開始的(從其他數字開始的也是同理計算),即按Code從小到大排序號,Code為1的行應該為第一行,Code為10的行應該在第10行,即Code=行號,
既然這樣,預覽數據如下:
刪除數據前的排號:
刪除數據后的排號:
很明顯發現,刪除數據前,Code=行號,刪除后Code不等于等號,而刪除數據后的第一行Code不等于行號的數據,即是第一個出現斷號的數據,即為我們想要查詢的結果。
如是,如果數據庫中有斷號,則可以用以下語句直接查出斷號:
結果立現。
這段代碼還存在一個缺陷,即此方法專用來處理有斷號的情況,如果不存在斷號時,應該返回Max(RowNumber)+1。正確代碼應該如下:
至此,我今天要講的基本結束,此處借用了SQL2005的方法row_number ,其他數據庫中也有類似的方法,大家可以自己摸索。
問題完全解決了嗎?大家可以發現,以上出現了斷號的情況,都是從小開始補號,比如3,7,8同時為斷號,則補3。假如有客戶要求從大號開始補號(即3,7,8斷號時,補8呢),怎么處理?
前面兩種通過C#方法操作的就很容易了,這里主要說一下通過SQL處理的方法:
那么再擴展一下,如何查出所有的斷號呢?
要實現這個功能,一般想法是將當前Code與上一行的Code進行對比,但由于可能出現連續斷號的情況(例如刪除了 Code=7、8、9三行)。此時該如何處理呢?
我的解決方法是,假如max(code)等于100,那么我先構造出100行(怎樣構造?數據庫中隨便找個行數大于100的表,select top 100就行了,如果沒有行數大于100的表,就聯合查詢構造出100行吧),再用這一100行的行號分別和code進行對比,如果存在Code<>行號的,即該處為斷裂號,示例如下:
假設系統中已經存在另一張表A,它的總行數>max(Code),【注:當然,如果不存在這樣的表,也可以通過select 的方式構造出來】,
查詢所有斷號的SQL如下:
至此,問題結束,以上代碼的優點在于只用一個SQL語句,而不需要用存儲過程、用戶自定義函數或C#中的循環,就可以解決各種斷號問題,當然為了性能方面還可以再做優化,在此不列出。
原文鏈接:http://www.cnblogs.com/Deper/archive/2011/06/10/2073909.html
【編輯推薦】