Centura SQLBase(又名 Gupta)中的 ROWNUM 等效項
我有一個 Centura SQLBase(版本 7,所以它已有 10 多年的歷史;現在顯然他們將名稱改回 Gupta),我需要在將數據複製到臨時表時將執行編號放入列中。
當分組程式碼更改時,執行編號必須重新啟動(因此每個組都有自己的計數器),數據必須按日期列排序。
這是一個轉換任務。對於測試(UAT),我只需要轉換部分數據庫(雖然它不是很大,所以我只想轉換全部)。對於上線,我將進行最終轉換,數據庫將被禁用。準確地說:這是一項兩次任務。儘管不是關鍵任務,但任何中斷對使用者來說都是煩人的,因為他們必須切換到論文,然後再鍵入(而不是立即鍵入)
本質上我有這些數據:
employee_no,date,group_code
我必須生成:
員工編號、日期、組程式碼、**組執行編號**
employee_no + date + group_code 是 PK。
在 Oracle 中,我會使用分析函式並一步完成,但在 SQLBase 中,我什至找不到像“rownum”這樣的東西。
我考慮使用該
SYSDBSequence.nextval
序列,但對於單個插入它保持不變(這可能是有道理的)。我考慮過使用它們
ROWID
(它包含一個唯一的行號,我知道如何挑選出來),但我不能ORDER BY
在INSERT-SELECT
組合中使用。ORDER BY
(也不允許創建視圖時)如果我不能用 SQL 解決這個問題,最後一種方法是使用電子表格。總共只有大約 400,000 行,但它肯定會相當慢且容易出錯。在最後的轉換日,我希望盡可能少的步驟。
如果我找不到
rownum
等價物,我可能會嘗試在 sqltalk 中編寫一個過程來進行 RBAR 處理。
在沒有視窗函式的 DBMS 中模擬行號的一種方法是使用三角形自連接。雖然它通常不是很有效。
鑑於主鍵是
(employee_no, date, group_code)
:SELECT a.employee_no, a.date, a.group_code, COUNT(*) AS group_running_number FROM tableX AS a JOIN tableX AS b ON a.group_code = b.group_code AND ( a.date > b.date OR a.date = b.date AND a.employee_no >= b.employee_no ) GROUP BY a.group_code, a.date, a.employee_no ;
上面用於分配行號的順序是:
(date ASC, employee_no ASC)
我認為索引
(group_code, date, employee_no)
會提高效率。
我再次檢查了文件並得出結論,在 Centura SQLBase 中沒有等效的 rownum(至少在那個舊版本中沒有;他們現在有一個 11.7 版)。
所以我硬著頭皮寫了一個程序來處理RBAR風格的數據(Row-By-Agonizing-Row),結果還不錯。處理我本地測試數據庫中的 300,000 行測試數據需要 3 分鐘。該過程沒有保存在任何地方,我只是在數據庫附帶的 SQL 客戶端“sqltalk”中執行它。也許對將來的某個人來說看看如何做到這一點會很有用:(長行可以用反斜杠分隔,但這會擾亂此處突出顯示的語法。僅供參考:我手動送出。)
procedure: createRunningNum Parameters receive number: nTotal receive string: sMessage Local Variables sql handle: hSql1 sql handle: hSql2 Number: nInd Number: nCount String: sROWID String: sGC String: sGCold Actions call SqlConnect(hSql1) call SqlConnect(hSql2) call SqlPrepareAndExecute(hSql1,'select rowid,group_code from TMP_TEST order by group_code,date_ into :sROWID, :sGC ') call SqlPrepare(hSql2,'update TMP_TEST set RunningNumber=:nCount where rowid=:sROWID') ! Note: if we set sGCold to a null-string, the condition "sGCold!=sGC" is always false! set sGCold='q#q@q! anything we can be sure not to encounter by chance' set nTotal=0 while SqlFetchNext(hSql1,nInd) if sGCold!=sGC set nCount=0 set sGCold=sGC set nCount=nCount+1 call SqlExecute(hSql2) set nTotal=nTotal+1 call SqlDisconnect(hSql1) call SqlDisconnect(hSql2) set sMessage='rows updated.' \ 42,anything /
為了將我的版本與 ypercube 的版本進行比較,我還按employee_no 訂購,並且確實收到了完全相同的結果。所以我相信 ypercube 的版本理論上可以工作,但它對於大型集合是不實用的(但鑑於該數據庫的能力有限,這是一個非常有創意的解決方案)。
觸發建議是另一個有趣的想法,但由於我已經有了一個快速的解決方案,我懷疑我是否會測試它。
僅供參考:Centura-SQLBase(版本 7)只有一個全域序列,它可能會跳轉。我從未調查過它是否會避免作為單個使用者出現漏洞,但我可以確認它在 2^32 增加後歸零。
所以我設想有一個額外的表來跟踪每個組的最大執行數。我將是唯一一個插入臨時表的人,所以不會有並發問題。只有大約 30 個組,我預計每次插入花費的時間大致恆定,並且隨著表的增長,每行的處理速度不會顯著降低。(轉換將是一個插入到臨時表的單次插入,其中觸發器負責處理執行號。)
我希望觸發器版本比超過一定大小的自連接更快,但不如我編寫的專門的“一次性”函式快。
我要感謝兩位貢獻者的創造性建議。