繁体   English   中英

Oracle 多次更换

[英]Oracle multiple replace

我在 Oracle 表中有未清理且一致的保修优惠列。 例如,在这个表中我们有以下数据,我只想保持最高保修期以月为单位(如果不是以月为单位,我想转换它)。 例如,从下面的第一个记录来看,18 个月是最高的,我想将数据保存在几个月内,因此“warranty_offrs”将为“18”,记录 #2 将是“12”而不是 12,记录 #6 将是“24”,值将是 integer 编号:

warranty_offrs (char 2000 字节):

  1. 记录#1:“一年18个月24周”
  2. 记录#2:“十二个月,八个月,六十天。”
  3. 记录#3:“(30)个月。”
  4. 记录#4:“(60)个月,20周。”
  5. 记录#5:“1年12个月18个月3年1个月”
  6. 记录 #6:“{12} 周,{2} 年,一个月,十二个月。”

数据有时在数月/天/周括号后带有点(因为它来自不同的来源),以及上面的各种组合。 我在存储过程中这样做,首先尝试使用替换来获取所有“(”“)”“[”“]”“{”“}”但仍然翻译。

我怎样才能实现它,请告诉我?

步骤 2-8 中使用的全局临时表仅包含相关列。

  1. 使用 REPLACE 命令从列中删除各种不相关的字符串,例如括号、点等,并将数据加载到 perm 表中。 一些列被转换为小写字母,以便以后计算。 此表包含所有列。

  2. 然后我使用您的 pivot 代码将 pivot 字符串值放入行中,例如,warranty_offrs 值“一个月,2 年,3 天”将变为 3 条记录,我将其加载到另一个标记为 {table_name_US_ENG} 的全局临时表中(因为存在相同的列在西班牙语中也是如此,有时它被填充,如果它被填充,那么我需要使用该列中的值)。

  3. 对西班牙列重复第 2 步,并在西班牙列有值时将仅透视的记录加载到全局临时 {table_name_ESP} 中。

  4. 创建的查找表有两列:单词、数字列,例如“一”、“1”、“十”、“10”等。这将有助于在步骤 5 中将单词转换为数字

  5. 来自第 2 步的数据和第 3 步表对第 4 步中的查找执行查找,并获取单词的数值。 “1”代表“一”,“10”代表“十”。 为了保持时间段(年/月等),我使用 substr 将两个值连接回来。 现在我所有的数值都是数字并且有期限(年/天)。 此数据被加载到另一个全局临时表中(将重复西班牙列值到单独的表)。

  6. 下一步是将它们转换为月份。 由于这些可能性很少,我使用 case 语句并将它们转换为月份,并加载到另一个全局临时表中(此步骤将针对西班牙数据重复)

  7. 然后我执行以下操作以从 us_eng GTT 表中获取 us_eng 列的最大月份:select id, max(mth_us_eng) keep (dense_rank first order by id)max_mth from gtt_table_us_eng。 然后将结果插入到全局临时表中。 (此 sql 对带有西班牙列的全局临时表重复以获得最大月份)

  8. 左外连接英语(左表)和西班牙语(右)表,并且只获取匹配插入到最后一个全局临时表的记录(呸!)

  9. 现在使用步骤 1 中的 perm 表和步骤 8 中的全局临时表执行 INNER JOIN,并将结果加载到最终 perm 表中。

问题:我们如何将数字与字符串分开? 在某些情况下,列值没有单个空格,而是像“18months”而不是“18months”。

注释:

  • 步骤 1 中有足够的 REPLACE 函数,而不是我邻居枫树中的分支。
  • 我希望我对 GTT 的使用不会加剧全球变暖。 (虽然我试图把 12 个月搞砸到 24 个月)。
  • 希望西班牙语列查找值提高了我下次访问墨西哥时的对话技巧。

欢迎任何调整代码的建议。 :)

很难调试你看不到的代码。 你说你写了一个存储过程,但它没有做你想要的。

更换支架很简单; 您可以使用嵌套的REPLACE (可以完成这项工作,但难以阅读和维护)或 - 更好的选择 - TRANSLATE

SQL> with test (wo) as
  2    (select '(60) months, [20] weeks.' from dual union all
  3     select '{12} weeks, {2} years' from dual
  4    )
  5  select replace(replace(replace(replace(replace(replace(
  6           wo, '(', ''), ')', ''), '[', ''), ']', ''), '{', ''), '}', '') result_1,
  7         --
  8         translate(wo, 'a()[]{}', 'a') result_2
  9  from test;

RESULT_1                 RESULT_2
------------------------ ------------------------
60 months, 20 weeks.     60 months, 20 weeks.
12 weeks, 2 years        12 weeks, 2 years

SQL>

您的问题的 rest 的一个:看起来该过程会很长,因为您必须涵盖许多不同的情况。 Go 循序渐进,经常测试。 我认为没有魔杖解决方案。


您(在评论中)询问您是否可以解析这些字符串。 是的; 因为它的每个部分都用逗号分隔,所以你会

SQL> with test (col) as
  2    (select '1 year, 12 months, 18 months, 3 years, one month' from dual)
  3  select trim(regexp_substr(col, '[^,]+', 1, level)) val
  4  from test
  5  connect by level <= regexp_count(col, ',') + 1;

VAL
------------------------------------------------
1 year
12 months
18 months
3 years
one month

SQL>

然后决定如何处理这些值。 正如我之前所说,你有单词和数字的组合,单数和复数,诸如此类 - go 一步一步改变你必须做的。 然后将最终结果合并回来,使用LISTAGG function。


如果您一次处理不止一行,那么您会得到很多重复的行。 在这种情况下,应相应地调整先前的查询。 下面是方法(我包括了额外的id列来显示哪个val属于哪一行):

SQL> with test (id, col) as
  2    (select 1, '1 year, 12 months, 18 months, 3 years, one month' from dual union all
  3     select 2, 'twelve months, 8 months, 60 days.' from dual
  4    )
  5  select id,
  6         trim(regexp_substr(col, '[^,]+', 1, column_value)) val
  7  from test cross join
  8    table(cast(multiset(select level from dual
  9                        connect by level <= regexp_count(col, ',') + 1
 10                       ) as sys.odcinumberlist))
 11  order by id, column_value;

        ID VAL
---------- ------------------------------------------------
         1 1 year
         1 12 months
         1 18 months
         1 3 years
         1 one month
         2 twelve months
         2 8 months
         2 60 days.

8 rows selected.

SQL>

[编辑,26.03.2021]

如果要在数字后面添加一个空格(如果它不存在,例如将18 months修改为18months ),则:

SQL> with
  2  test (col) as
  3    (select 'one year, 18months, 24 weeks' from dual),
  4  temp as
  5    -- split it to rows (you already know how to do that)
  6    (select trim(regexp_substr(col, '[^,]+', 1, level)) val
  7     from test
  8     connect by level <= regexp_count(col, ',') + 1
  9    )
 10  -- in CASE, check whether VAL contains a space. If so, return VAL. If not,
 11  -- add a space after digits
 12  select
 13    val,
 14    case when instr(val, ' ') = 0 then regexp_replace(val, '(\d+)', '\1 ')
 15         else val
 16    end new_val
 17  from temp;

VAL        NEW_VAL
---------- ----------
one year   one year
18months   18 months
24 weeks   24 weeks

SQL>

此外,也许您不需要将数字转换为单词的映射表 - 有一个查询可以让您做到这一点; 看看你能不能用。

SQL> with test (col) as
  2    (select   1 from dual union all
  3     select  18 from dual union all
  4     select  24 from dual union all
  5     select 673 from dual
  6    )
  7  select col,
  8         to_char(to_date(col, 'j'),'jsp') in_words
  9  from test;

       COL IN_WORDS
---------- ---------------------------------------------------
         1 one
        18 eighteen
        24 twenty-four
       673 six hundred seventy-three

SQL>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM