oracle 函数生成字母数字字符串

trnvg8h3  于 2023-04-20  发布在  Oracle
关注(0)|答案(2)|浏览(155)

我被要求创建一个函数,它循环遍历字母表A-Z(仅大写),并将其与TIMESTAMP的小数部分连接起来。该函数应始终生成唯一的字符串。
函数是否可以在生成值之前使用not EXISTS之类的东西,从而保证唯一性?我想保留字符串的alpha部分,并生成TIMESTAMP的新小数部分。基本上,函数中的重试逻辑?
最终结果应该会生成一个类似于下面的示例输出
A432635 B227541 C986435...... Z 885525回A A543422 B 008545
我超出了我的联盟,希望有人能帮助我。我下面的尝试是不正确的,因为它是增加字符串的alpha部分的大小,一旦我通过'Z'。

SELECT       RPAD (SUBSTR ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                          ,DECODE (MOD ( ROWNUM, 26), 0, 26, MOD ( ROWNUM, 26))
                          ,1)
                  ,FLOOR ( (ROWNUM - 1) / 26) + 1
                  ,SUBSTR ('ABCDEFGHIJKLMNOPQRSTUVWXYZ'
                          ,DECODE (MOD ( ROWNUM, 26), 0, 26, MOD ( ROWNUM, 26))
                          ,1))
      FROM   DUAL
CONNECT BY   LEVEL <= 130;
f3temu5u

f3temu5u1#

我被要求创建一个函数,它循环遍历字母表A-Z(仅大写),并将其与TIMESTAMP的小数部分连接起来。
你可以把函数写成:

CREATE SEQUENCE sequence_name;

CREATE FUNCTION alphanum_string RETURN VARCHAR2
IS
BEGIN
  RETURN CHR(MOD(sequence_name.NEXTVAL - 1, 26) + 65)
      || TO_CHAR(SYSTIMESTAMP, 'FF6');
END;
/

这个函数应该总是生成一个唯一的字符串。
不要将你的想法用于函数,因为它最终会产生重复的值。
或者只使用一个序列:

CREATE SEQUENCE sequence_name;

CREATE FUNCTION get_sequence_value RETURN NUMBER
IS
BEGIN
  RETURN sequence_name.NEXTVAL;
END;
/

或使用GUID:

CREATE FUNCTION get_guid_string RETURN VARCHAR2
IS
BEGIN
  RETURN SYS_GUID();
END;
/

但是,在这两种情况下,您都不需要函数,可以直接使用sequence_name.NEXTVALCAST(SYS_GUID() AS VARCHAR2)
如果你确实想要一个随机的UUID,那么你可以在数据库中使用Java(如果它被启用):

CREATE AND COMPILE JAVA SOURCE NAMED JavaUUID AS
public class JavaUUID {
  public static String generate(){
    return java.util.UUID.randomUUID().toString().toUpperCase();
  }
}
/

CREATE FUNCTION UUID RETURN VARCHAR2
  AS LANGUAGE JAVA NAME 'JavaUUID.generate() return java.lang.String';
/

然后:

SELECT sequence_name.NEXTVAL AS seq,
       CAST(SYS_GUID() AS VARCHAR2(32)) AS guid,
       UUID() as uuid
FROM   DUAL
CONNECT BY LEVEL <= 10;

输出:
| SEQ|GUID|UUID|
| --------------|--------------|--------------|
| 1|F966F1759FD0956EE053182BA8C0A4A5|F16B2AF4-E5ED-4E13-932F-1F29CA3008CC|
| 二|F966F1759FD1956EE053182BA8C0A4A5|329DF39D-3FB8-4AEF-BF63-46BA51F7709D|
| 三|F966F1759FD2956EE053182BA8C0A4A5|E41DA8EB-2F1B-4488-8D83-0A6D8778C79B|
| 四|F966F1759FD3956EE053182BA8C0A4A5|CCD51797-7FF4-46A1-9AB4-1FBD9DCED447|
| 五|F966F1759FD4956EE053182BA8C0A4A5|73D8C9C9-2BE3-471E-8279-A8A756181B77|
| 六|F966F1759FD5956EE053182BA8C0A4A5|724B1CAC-99BF-4884-8640-0514D5A15D5C|
| 七|F966F1759FD6956EE053182BA8C0A4A5|FBE3B326-4544-4A24-A302-00BD360A52AB|
| 八|F966F1759FD7956EE053182BA8C0A4A5|CE8FCB97-34D3-455B-B628-2DB90951AC7C|
| 九|F966F1759FD8956EE053182BA8C0A4A5|0464268C-9119-4F98-A603-BAA3088FB946|
| 10个|F966F1759FD9956EE053182BA8C0A4A5|811A5197-1C12-4EC1-8704-DB15CBE7C254|
fiddle

0pizxfdo

0pizxfdo2#

你没有解释为什么要这么做,因为,如果是关于唯一性的,有比创建你自己的唯一字符串更简单的方法,而这个字符串迟早会失败,为了检测它,你必须做一些编程。
因此,我建议您:

  • 使用标识列并让Oracle自己处理它
  • 或者,使用序列(手动或创建一个将处理它的触发器)
  • 如果它看起来像你说的那样(字母+时间戳),使用日期和时间组件,因为它将使唯一性冲突不太可能发生(除非你一次处理许多值,Oracle真的很快,所以你得到相同的时间戳)

如果上面的任何一个都不能接受,那么这里有一个你可以使用的选项;有一个表包含以前创建的唯一字符串。函数是一个自治事务,因此它可以插入和提交唯一字符串;它还检查是否存在新创建的字符串-不是通过潜在的缓慢选择,而是直接插入,这将在唯一索引上失败。在这种情况下,去获取另一个值。

SQL> create table robin
  2    (id        number generated always as identity,
  3     value     varchar2(7),
  4     --
  5     constraint pk_robin primary key (id),
  6     constraint uk_robin unique (value)
  7    );

Table created.

SQL> -- insert the 1st row manually, to simplify function's code
SQL> insert into robin (value) values ('A' || to_char(sysdate, 'hh24miss'));

1 row created.

SQL> commit;

Commit complete.

功能:

SQL> create or replace function f_robin
  2    return varchar2
  3  is
  4    pragma autonomous_transaction;
  5    l_letter   varchar2(1);  -- first character in that "unique string"
  6    retval     varchar2(7);  -- return value
  7  begin
  8    loop
  9    begin
 10      -- get first character
 11      select substr(value, 1, 1)
 12        into l_letter
 13        from robin
 14        order by id desc
 15        fetch first 1 rows only;
 16      -- if 1st character is Z, start a new one with A; else, take letter that
 17      -- follows L_LETTER
 18      retval := case when l_letter = 'Z' then 'A'
 19                     else chr(ascii(l_letter) + 1)
 20                end || to_char(sysdate, 'hh24miss');
 21      -- insert newly created value into the table. If insert succeds, return
 22      insert into robin (value) values (retval);
 23      commit;
 24      return retval;
 25    exception
 26      -- insert failed (because uniqueness was violated); go get another value
 27      when dup_val_on_index then
 28        null;
 29    end;
 30    end loop;
 31  end;
 32  /

Function created.

测试:

SQL> declare
  2    l_value varchar2(7);
  3  begin
  4    for i in 1 .. 30 loop
  5      l_value := f_robin;
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

结果:

SQL> select * from robin order by id;

        ID VALUE
---------- -------
         1 A213624
         2 B213624
         3 C213624
         4 D213624
         5 E213624
         6 F213624
         7 G213624
         8 H213624
         9 I213624
        10 J213624
        11 K213624
<snip>
        25 Y213624
        26 Z213624
       304 A213625
       305 B213625
       306 C213625
       307 D213625
       308 E213625

31 rows selected.

SQL>

相关问题