【问题标题】:Split CLOB to multiple VARCHAR2 columns by separator通过分隔符将 CLOB 拆分为多个 VARCHAR2 列
【发布时间】:2019-09-23 05:20:29
【问题描述】:

我有一个带有列的表格:

  • f_name - Varchar
  • f_content - CLOB

表1

f_name     f_content
test1.txt  YL*1**50*1~
           RX*1~
           LR*2~
test2.txt  YL*1**49*1~
           EE*1~
           WW*2~

f_content 超过 4000 个字符,有时超过 10000 个字符。

是否可以创建 3 个 Varchar2 列并在每列中拆分最多 4000 个字符,直到最近的 ~ 覆盖整个 CLOB?

输出将是:

f_name     f_content       f_content_varchar1    f_content_varchar2    f_content_varchar3
test1.txt  YL*1**50*1~     YL*1**50*1~           RX*1~                  LR*2~
           RX*1~
           LR*2~
test2.txt  YL*1**49*1~      YL*1**49*1~         EE*1~                   WW*2~
           EE*1~
           WW*2~

请注意 - 我想把它分成 3 列,但只到最后一个 ~,所以例如,如果一行在字符 4003 上结束 ~,那么它不应该将最后一行添加到 varchar 列并始终考虑前一行以~结尾。

一个例子是:

YL*1**50*1~
RX*1~
LR*2~

假设 4000 个字符以

结尾
"YL*1**50*1~
RX*1~
LR"

那么在varchar column1中,它应该存储:

"YL*1**50*1~
RX*1~"

并且在 varchar column2 中,它应该存储:

"LR*2~"

【问题讨论】:

  • 您可以使用 SUBSTRING() 方法将 f_content 中的值拆分为其他 3 列。首先从 0 拆分到 4000,然后从 4001 拆分到 8000,最后从 8001 拆分到 12000。
  • 我想要直到最后一个 ~ 直到 4000 并且没有额外的字符,即使它是 3945 个字符。从 3946 到 ~ 7946。
  • 如果4000个字符之间有2个~怎么办?
  • 我的意思是直到最后一个〜。一个clob中会有很多〜。我只想到4000。
  • 我添加了一个例子。不确定这是否有意义。

标签: sql oracle split


【解决方案1】:

如果您可以使用 CURSOR 来操作多行,以下脚本可以通过提供想法来帮助您。请注意,我考虑了 20,40 和 60 的终点。

重要提示:请先在您的测试数据库上测试此脚本

重要提示:在 SELECT 语句中添加必要的 WHERE 条件。否则将选择所有记录

DECLARE @NAME NVARCHAR(MAX)
DECLARE @F_NAME NVARCHAR(MAX)

DECLARE @CUT_1 INT
DECLARE @CUT_2 INT


DECLARE db_cursor CURSOR FOR 
SELECT f_name,f_content 
FROM your_table 
--WHERE Plese add conditions to pick only columns you wants to adjust 

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @F_NAME,@NAME  

WHILE @@FETCH_STATUS = 0  
BEGIN  

    DECLARE @A TABLE (POS INT)
    DECLARE @POS INT
    DECLARE @OLDPOS INT
    SELECT @OLDPOS=0        

    SELECT @POS=PATINDEX('%~%',@name) 
    WHILE @POS > 0 AND @OLDPOS <> @POS
     BEGIN
       INSERT INTO @A VALUES (@POS)
       SELECT @OLDPOS=@POS
       SELECT @POS=PATINDEX('%~%',SUBSTRING(@NAME,@POS + 1,LEN(@NAME))) + @POS
    END

    SELECT @CUT_1 = ISNULL(MAX([pos]),4000) from @a where pos <= 4000
    SELECT @CUT_2 = ISNULL(MAX([pos]),@CUT_1+4000) from @a where pos > @CUT_1 AND pos <= @CUT_1+4000


    UPDATE your_table
    SET [f_content_varchar1] = SUBSTRING(@Name,1,@CUT_1),
        [f_content_varchar2] = SUBSTRING(@Name,@CUT_1+1,@CUT_2-@CUT_1),
        [f_content_varchar3] = SUBSTRING(@Name,@CUT_2+1,12000-@CUT_2) 
    WHERE f_name = @F_NAME

    DELETE FROM @A
    SET @POS = NULL
    SET @OLDPOS = NULL
    SET @OLDPOS = NULL


    FETCH NEXT FROM db_cursor INTO  @F_NAME,@NAME 
END 

CLOSE db_cursor  
DEALLOCATE db_cursor 

【讨论】:

  • 如何将它应用到桌子上?
  • 您必须先使用光标选择所有需要的行。然后应用上述条件并将最终输出值保存到新的 3 列。如果您需要 CURSOR 方面的帮助,请告诉我。
  • 是的,我需要帮助。
  • 脚本已更新。请检查描述中的 2 重要说明。
  • Ops... 可能需要对语法进行一些更改。我不是甲骨文专家:(
【解决方案2】:

如果只关心前 4000 个字符,则将值转换为 varchar2(),然后使用正则表达式:

select t1.*,
       regexp_substr(f_content_str, '[^~]+[~]', 1, 1) as part1,
       regexp_substr(f_content_str, '[^~]+[~]', 1, 2) as part2,
       regexp_substr(f_content_str, '[^~]+[~]', 1, 3) as part3
from (select t1.*,
             dbms_lob.substr(t1.f_content, 4000, 1)  as f_content_str
      from t
     ) t;

【讨论】:

  • 我实际上想要整个 CLOB 值。不能只有前 4000 个。
  • @dang 。 . . “是否可以创建 3 个 Varchar2 列并将 4000 个字符拆分到最近的〜?”
  • 我的意思是每个 4000 个,很抱歉造成混乱。
猜你喜欢
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 1970-01-01
  • 2021-03-05
  • 2023-01-13
相关资源
最近更新 更多