格式化没有 REGEXP_REPLACE 和 PL/SQL 的 UUID 字符串

Formating UUID String without REGEXP_REPLACE and PL/SQL

我想按照 this answer

中的建议格式化 sys_guid() 函数的结果
select regexp_replace(rawtohex(sys_guid())
       , '([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})'
       , '----') 
         as FORMATTED_GUID 
 from dual

出于性能原因,我想避免使用 regexp_replace(因为我要处理大量记录)。

我的场景可以简化为这个用例:

 select rawtohex(sys_guid()) GUID
 from dual connect by level <= 2;

显然我不能使用 substr 和串联,因为每个 SUBSTR 会处理不同的 SYS_GUID。我还想留在 SQL,无需上下文切换到 PL/SQL 函数。

知道如何使用掩码将 SQL 中的字符串格式化为类似于日期或数字的格式:

 to_char(rawtohex(sys_guid(),'CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC') /* note, this is clear illegal */

不幸的是,您不能在数字格式中包含字符串文字,否则您可以将十六进制字符串转换为数字然后再转换回来,在格式掩码中的正确位置插入文字 - 但您只能这样做日期。

你可以使用substr(),因为位置是固定的。你担心

Obviously I can't use substr and concatenation as each SUBSTR would process a different SYS_GUID.

使用子查询分解(a.ka。常见的 table expression/CTE)意味着 substr() 调用来自该 CTE 的行都看到相同的 GUID;此方法不会为每个生成新的 SYS_GUID。

with t as (
  select rawtohex(sys_guid()) guid from dual
  connect by level <= 2
)
select guid, substr(guid, 1, 8)
  ||'-'|| substr(guid, 9, 4)
  ||'-'|| substr(guid, 13, 4)
  ||'-'|| substr(guid, 17, 4)
  ||'-'|| substr(guid, 21, 12) as formatted_guid
from t;

GUID                             FORMATTED_GUID                         
-------------------------------- ----------------------------------------
2F6BA62518F926D0E0534D49E50ABB46 2F6BA625-18F9-26D0-E053-4D49E50ABB46    
2F6BA62518FA26D0E0534D49E50ABB46 2F6BA625-18FA-26D0-E053-4D49E50ABB46    

这比处理大量数据的正则表达式要快得多。循环中有 100000 个值(在 PL/SQL 块中,在循环内做最少的工作以使其实际正确评估,并使用 dbms_utility.get_cpu_time 检查经过的时间)正则表达式版本大约需要2.51 秒,而子字符串版本大约需要 0.29 秒。你的系统当然会得到不同的数字,但它应该仍然是大约相同的数量级。