postgresql 创建顺序为AAB、AA1、AA9、阿坝的序列[已关闭]

eqqqjvef  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(3)|浏览(134)

**已关闭。**此问题需要debugging details。当前不接受答案。

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
7天前关闭。
Improve this question
我正在尝试创建存储在数据库中的序列。因此,只需一个服务调用,我就应该按顺序获得新的序列,如AAB。下一个调用应该返回AAC,下一个AAD...... AA9,阿坝......我尝试创建三个数字序列0〈=first_seq〈36,也像这个second_seq,third_seq。我正在使用Spring Hibernate,postgresql。

pbossiut

pbossiut1#

你的问题很含糊你应该至少指明需要Java或Postgres解决方案。下面给出了一个完全通用的Postgres解决方案,只给出了前面的 sequence 和一个带有有序数字集的字符串。它创建了2个CTE,第一个定义了数字,然后第二个“构建”了一个工作变量集。最后,主sql构建了下一个序列。这是在一个语句中处理的,嵌套在一个sql函数中。(请参阅demo

create or replace function strange_sequence_nextval(current_seq_in text)
     returns text 
    language sql
    immutable
as $$
   with avail_set (k_ent) as ( values('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') )
      , parms_set (k_ent, k_len, l_pos, l_len, l_val) as 
        (select k_ent
              , length(k_ent) 
              , position(right(current_seq_in, 1) in (k_ent) )
              , length(current_seq_in)
              , left(current_seq_in, length(current_seq_in)-1)
           from avail_set 
        ) 
    select case when current_seq_in is  null then left(k_ent,1) 
                when l_pos = k_len           then concat( strange_sequence_nextval(l_val), left(k_ent,1)) 
                when l_len < 2               then substr( k_ent, l_pos+1, 1)
                else                              concat( l_val, substr( k_ent, l_pos+1, 1)) 
           end
      from parms_set;
$$;

注意:作为一个SQL函数,它可以作为一个独立的语句被提取和运行。您只需要将 * 当前序列 * 作为一个参数传递。
编辑:回复Vérace。我没有得到生成整个序列,因为如所述 Next call应该返回AAC,next(call)AAD ...。此外,来自... AA9, ABA...的序列没有结尾。但不需要修改函数,您可以在递归查询中使用它。

with recursive seq_gen(seq, gen_no, stop_at) as
     ( select 'AAA', 1, 100         -- or any other random point
       union all 
       select strange_sequence_nextval(seq), gen_no+1, stop_at 
         from seq_gen 
        where gen_no < stop_at        
    )
select seq
  from seq_gen;
g6baxovj

g6baxovj2#

试试这个。

static final String DIGITS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static final int LENGTH = 3;
static int SEED = 0;

public static String nextSequence() {
    int size = DIGITS.length();
    char[] buffer = new char[LENGTH];
    for (int n = ++SEED, i = LENGTH - 1; i >= 0; --i, n /= size)
        buffer[i] = DIGITS.charAt(n % size);
    return new String(buffer);
}

for (int i = 0; i < 8; ++i)
    System.out.println(nextSequence());

输出功率

AAB
AAC
AAD
AAE
AAF
AAG
AAH
AAI
643ylb08

643ylb083#

首先,我这样做了(下面的所有代码都是here)。

SELECT
  SUBSTRING('ABCDE123', s.i, 1) AS c1,
  SUBSTRING('ABCDE123', t.j, 1) AS c2,
  SUBSTRING('ABCDE123', u.k, 1) AS c3
FROM
  GENERATE_SERIES(1, 8) AS s(i),
  GENERATE_SERIES(1, 8) AS t(j),
  GENERATE_SERIES(1, 8) AS u(k)
ORDER BY c1, c2, c3
LIMIT 10;

结果:

c1  c2  c3
1   1   1
1   1   2
1   1   3
1   1   A
1   1   B
...
... snipped for brevity
...

但是,您希望它排序为AAAAAB...但是1在ASCII表中位于A之前,因此我们必须执行以下操作:

WITH cte1 AS
(
  SELECT

    SUBSTRING('ABCDE123', s.i, 1) AS c1,
    SUBSTRING('ABCDE123', t.j, 1) AS c2,
    SUBSTRING('ABCDE123', u.k, 1) AS c3

  FROM
    GENERATE_SERIES(1, 8) AS s(i),
    GENERATE_SERIES(1, 8) AS t(j),
    GENERATE_SERIES(1, 8) AS u(k)
)
SELECT 
  c1 || c2 || c3 AS sequence
FROM
  cte1
ORDER BY 

  CASE
    WHEN ASCII(c1) < 58 THEN ASCII(c1) + 45 --  45 is arbitrary, as long as it gets
    ELSE ASCII(c1)                          --  (ASCII(c1) + 45 > 90). Check an ASCII table!
  END,

  CASE
    WHEN ASCII(c2) < 58 THEN ASCII(c2) + 45
    ELSE ASCII(c2)
  END,

  CASE
    WHEN ASCII(c3) < 58 THEN ASCII(c3) + 45
    ELSE ASCII(c3)
  END
LIMIT 10;

结果:

sequence
AAA
AAB
AAC
AAD
AAE
AA1
...
... snipped for brevity
...

这样,我们就有了正确的排序顺序。
我们可以把所有这些放在一个函数中,如下所示:

CREATE OR REPLACE FUNCTION seq(str TEXT)
RETURNS SETOF TEXT
LANGUAGE SQL IMMUTABLE
AS
$$
  WITH cte1 AS
  (
    SELECT

      SUBSTRING($1, s.i, 1) AS c1,
      SUBSTRING($1, t.j, 1) AS c2,
      SUBSTRING($1, u.k, 1) AS c3

    FROM
      GENERATE_SERIES(1, LENGTH($1)) AS s(i),
      GENERATE_SERIES(1, LENGTH($1)) AS t(j),
      GENERATE_SERIES(1, LENGTH($1)) AS u(k)  
  )

  SELECT 
    c1 || c2 || c3 AS sequence
  FROM
  cte1
  ORDER BY 

    CASE
      WHEN ASCII(c1) < 58 THEN ASCII(c1) + 45  -- <<= 45 is arbitrary, as long as it gets
      ELSE ASCII(c1)                           --     it above 90. Check an ASCII table!
    END,

    CASE
      WHEN ASCII(c2) < 58 THEN ASCII(c2) + 45
      ELSE ASCII(c2)
    END,

    CASE
      WHEN ASCII(c3) < 58 THEN ASCII(c3) + 45
      ELSE ASCII(c3)
    END
$$;

和运行:

SELECT
  seq('ABC1')
  LIMIT 10;

结果:

seq
AAA
AAB
AAC
AA1
ABA
ABB
...
... snipped for brevity
...

感谢@Belayer的code为我们提供了功能上的灵感!

相关问题