Oracle sql Order By number 和 char inside

Oracle sql Order By number and char inside

我是 sql 的新手,所以我不完全理解我在做什么。我的问题是,我如何按此数据排序,该顺序将按数字排序,如 1、2、3,但里面有字母,所以它会像 1、2、A3、B3、4。

到目前为止我有这个:

订购方式 REGEXP_REPLACE(TRIM(REGEXP_SUBSTR(string, '\d', 1, 1)),'(\d+.)(\d+.)?(\d+.)?( \d+.)?', '\1') 空值优先, REGEXP_REPLACE(TRIM(REGEXP_SUBSTR(string, '\d', 2, 2)),'(\d+.)(\d+.)?(\d+.)?( \d+.)?', '\2') 空值优先, REGEXP_REPLACE(TRIM(REGEXP_SUBSTR(string, '\d', 3, 3)),'(\d+.)(\d+.)?(\d+.)?( \d+.)?', '\3') 空值优先, REGEXP_REPLACE(TRIM(REGEXP_SUBSTR(string, '\d', 4, 4)),'(\d+.)(\d+.)?(\d+.)?( \d+.)?', '\4') 空值优先, REGEXP_REPLACE(TRIM(REGEXP_SUBSTR(string, '\d', 5, 5)),'(\d+.)(\d+.)?(\d+.)?( \d+.)?', '\5') 空值优先, 字符串

它一直有效,直到我们有第三级小数,例如 2.7.1.,然后它变成 2.1、2.2...2.7、2.8、2.7.1.、2.7.2。我不知道我是否解释正确所以我也有照片 :D

当它像这样工作时: Picture of Working sort

Picture of Working sort

但是我们有像 2.7.1., 2.7.2 这样的数字。 Picture with incorrect sort

所以计划是它也会用字符串对数字进行排序,例如:1,2,A3,A3.1, A3.1.1。 B3,B3.1,4.1, 4.1.1, 4.1.2...

非常感谢您的帮助和解释。

眼前的问题是您正在增加位置和出现次数;所以

REGEXP_SUBSTR(string, '\d', 2, 2)

应该是

REGEXP_SUBSTR(string, '\d', 1, 2)

但是您过于复杂化了,并且在提取或排序时没有处理 multiple-digit 元素,因为没有任何内容被视为数字。

我认为这符合您的要求:

ORDER BY
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 1)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 2)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 3)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 4)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 5)) nulls first,
  string

db<>fiddle


如果只有第一个元素可以一个字符(或多个字符)开头,那么您只需在第一个数字后添加一个检查即可:

ORDER BY
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 1)) nulls first,
  REGEXP_SUBSTR(string, '^\w+', 1, 1) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 2)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 3)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 4)) nulls first,
  TO_NUMBER(REGEXP_SUBSTR(string, '\d+', 1, 5)) nulls first

这将订购 3,A3,A3.1,B3

您现在可能不需要最后的 string

db<>fiddle

您主要需要的是了解如何解决这个问题。作为一个人,我可以很容易地看出你在对这些字符串进行排序:1,2,A3,A3.1, A3.1.1。 B3、B3.1、4.1、4.1.1、4.1.2...,但计算机不会知道 A3 应被视为 3 加一点,而 B3 应被视为 3 加一点。由于这些是字符串,当涉及到超过一位的数字时,计算机也不会理解为什么“2”排在“10”之前,因为字符串“10”以“1”开头,而字符串“2”以“2”开头,在“1”之后。

让我们从第一个问题开始。计算机看不到 '3' < 'A3' < 'B3' < '4',但它会看到 '3' < '3A' < '3B' < '4'。那为什么不换位置呢:

REGEXP_REPLACE(col, '([[:alpha:]])([[:digit:]]+)', '')

那么就要解决第二个问题了。计算机看不到“1”<“2”<“10”,但它会看到“01”<“02”<“10”。因此,最佳情况下我们会在所有数字前加上前导零,这样它们都具有相同的长度。为此,我们必须知道数字允许的最长长度。假设它是三个地方,比如'123'和'B123'。然后我们必须将所有数字设为三位数('012'、'012A'、'123'、'123B')。不幸的是,正则表达式不能做到这一点(或者我不知道怎么做)。我必须编写一些硬代码:“找到 one-digit 个数字并将它们设为 three-digit 个数字”和“找到 two-digit 个数字并将它们设为 three-digit 个数字”。而且我仍然必须通过先添加不必要的零然后再次删除它们来欺骗自己。

这里是整个组合:

select
  col, 
  regexp_replace(
    regexp_replace(
      regexp_replace(
        regexp_replace(col,
                       '([[:alpha:]])([[:digit:]]+)',
                       '' -- step 1: switch number / alpha positions
        ),
        '([[:digit:]]+)',
        '00' -- step 2: precede all numbers with two zeros
      ),
      '0([[:digit:]]{4,4})',
      '' -- step 3: remove one leading zero from five-digit numbers
    ),
    '0([[:digit:]]{3,3})',
    '' -- step 4: remove one leading zero from (now) four-digit numbers
  ) as sortkey
from mytable
order by sortkey;

演示:https://dbfiddle.uk/?rdbms=oracle_21&fiddle=dd21d406a88846285fed1d3c05595417

或者写一个PL/SQL函数来生成排序键。