Query

Centura SQLBase(又名 Gupta)中的 ROWNUM 等效項

  • November 1, 2018

我有一個 Centura SQLBase(版本 7,所以它已有 10 多年的歷史;現在顯然他們將名稱改回 Gupta),我需要在將數據複製到臨時表時將執行編號放入列中。

當分組程式碼更改時,執行編號必須重新啟動(因此每個組都有自己的計數器),數據必須按日期列排序。

這是一個轉換任務。對於測試(UAT),我只需要轉換部分數據庫(雖然它不是很大,所以我只想轉換全部)。對於上線,我將進行最終轉換,數據庫將被禁用。準確地說:這是一項兩次任務。儘管不是關鍵任務,但任何中斷對使用者來說都是煩人的,因為他們必須切換到論文,然後再鍵入(而不是立即鍵入)

本質上我有這些數據:

employee_no,date,group_code

我必須生成:

員工編號、日期、組程式碼、**組執行編號**

employee_no + date + group_code 是 PK。

在 Oracle 中,我會使用分析函式並一步完成,但在 SQLBase 中,我什至找不到像“rownum”這樣的東西。

我考慮使用該SYSDBSequence.nextval序列,但對於單個插入它保持不變(這可能是有道理的)。

我考慮過使用它們ROWID(它包含一個唯一的行號,我知道如何挑選出來),但我不能ORDER BYINSERT-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 個組,我預計每次插入花費的時間大致恆定,並且隨著表的增長,每行的處理速度不會顯著降低。(轉換將是一個插入到臨時表的單次插入,其中觸發器負責處理執行號。)

我希望觸發器版本比超過一定大小的自連接更快,但不如我編寫的專門的“一次性”函式快。

我要感謝兩位貢獻者的創造性建議。

引用自:https://dba.stackexchange.com/questions/49382