SQL挑战/解谜:如何将ASCII艺术范围转换为关系数据?

时间:2016-10-10 19:26:59

标签: sql regex teradata ascii-art

  • 这一挑战的动机是轻松准确地模拟以某种方式相互关联的IP范围数据集。

挑战

表包含单列文本类型。 该文本包含一行或多行,其中每行包含一个或多个由短划线创建的部分。 目标是编写一个查询,为每个部分返回一个元组及其起点和终点。

E.g。

'
--- -- -
 ----
'
  • 上面的文字包含2行。
  • 它包含4个部分。
  • 第1行包含3个部分。
  • 第二行包含1个部分。
  • 第一行的元组是(1,3),(5,6),(8,8)。
  • 第二行的元组是(2,5)。

要求

  • 解决方案应该是单个SQL查询(子查询很好)。
  • 不允许使用T-SQL,PL / SQL等
  • 不允许使用UDF(用户自定义函数)

  • 如果需要,我们可能会假设表中只有一条记录。

样本数据

create table t (txt varchar (1000) not null);

insert into t (txt) values 
(
'
 --- ---  ---   ---
----------          -
 - - -- -- --- ---
      ----- ---- --- -- -
   -------
' 
);

请求结果

*只需要最后2列(section_start / end),其余列用于调试目的。

line_ind    section_ind section_length  section_start   section_end
--------    ----------- --------------  -------------   -----------
1           1           3               2               4
1           2           3               6               8
1           3           3               11              13
1           4           3               17              19
2           1           10              1               10
2           2           1               21              21
3           1           1               2               2
3           2           1               4               4
3           3           2               6               7
3           4           2               9               10
3           5           3               12              14
3           6           3               16              18
4           1           5               7               11
4           2           4               13              16
4           3           3               18              20
4           4           2               22              23
4           5           1               25              25
5           1           7               4               10

3 个答案:

答案 0 :(得分:0)

的Teradata

with        l
            as
            (
                select      line_ind
                           ,line

                from        table
                            (
                                regexp_split_to_table (-1,t.txt,'\r','')
                                returns (minus_one int,line_ind int,line varchar(1000))
                            )   
                            as l
            )

select      l.line_ind
           ,s.section_ind                                           
           ,regexp_instr    (l.line,'\S+',1,s.section_ind,0)        as section_start
           ,regexp_instr    (l.line,'\S+',1,s.section_ind,1) - 1    as section_end
           ,char_length     (s.section)                             as section_length

from        table
            (
                regexp_split_to_table (l.line_ind,l.line,'\s+','')
                returns (line_ind int,section_ind int,section varchar(1000))
            )  
            as s
           ,l

where       l.line_ind  =
            s.line_ind

order by    l.line_ind
           ,s.section_ind   
;

答案 1 :(得分:0)

Oracle

 SELECT row_n AS line_ind 
   ,dense_rank() over(PARTITION BY row_n ORDER BY s_beg) AS section_ind 
   ,s_end - s_beg AS section_length   
   ,s_beg - decode(row_n, 0, 0, instr(a,chr(10),1,row_n))  AS section_start   
   ,s_end - decode(row_n, 0, 0, instr(a,chr(10),1,row_n)) -1  AS section_end 
  FROM   (SELECT a 
           ,s_beg 
           ,DECODE(s_end, 0, length(a) + 1, s_end) AS s_end 
           ,length(substr(a, 1, s_beg)) 
              - length(REPLACE(substr(a, 1, s_beg), chr(10))) AS row_n 
           ,lvl 
     FROM   (SELECT txt as a 
                   ,DECODE(LEVEL, 1, 0, regexp_instr(txt , '\s|\n', 1, LEVEL - 1)) + 1 AS s_beg 
                   ,regexp_instr(txt , '\s|\n', 1, LEVEL) AS s_end 
                   ,LEVEL AS lvl 
             FROM   t 
             CONNECT BY LEVEL <= length(txt ) - length(regexp_replace(txt , '\s|\n')) + 1) 
     )WHERE  s_beg != s_end;

答案 2 :(得分:0)

的Oracle

select      regexp_instr (txt,'-+',1,level,0)       - instr (txt,chr(10),regexp_instr (txt,'-+',1,level,0) - length (txt) - 1,1)   as section_start
           ,regexp_instr (txt,'-+',1,level,1) - 1   - instr (txt,chr(10),regexp_instr (txt,'-+',1,level,0) - length (txt) - 1,1)   as section_end

from        t

connect by  level <= regexp_count (txt,'-+')
;
相关问题