我认为直到今天才理解正则表达式。
(我也在OTN上发布了这个,但我认为在stackoverflow上有更广泛的受众)
我有一个包含大量代码的列,第二列略微提示了层次结构应该是什么。
CREATE TABLE REGEXTEST
( ITEM VARCHAR(200),LEV INT);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4',1);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-1',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-10',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-11',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-12',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-13',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-14',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-15',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-15-59A7',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-15-59D7',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-15-59F7',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('4245-4-15-5987',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285',1);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285-20',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285-30',2);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285-30-5',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285-30-5/20',3);
INSERT INTO REGEXTEST (ITEM,LEV) VALUES ('1090-81/5285-30-6/25',3);
我需要构建父/子的层次结构,其中父级由级别确定。更复杂的是,有时候会有一个斜线/分隔级别,有时会出现连字符。但连字符和破折号并不一定意味着水平的变化。
我将解释最简单的场景(使用4245样本数据)。
4245-4是第一级。都好。 4245-4-1是2级。所以孩子的名字是4245-4-1,其父母的名字是4245-1。我希望结果是ParentColumn,ChildColumn。我正在使用这些数据构建目录结构。所以继续使用相同的例子:Parent Child
4245-4
4245-4 4245-4-1
4245-4 4245-4-10
4245-4 4245-4-11
4245-4 4245-4-12
4245-4 4245-4-15
4245-4-15 4245-4-15-59A7
4245-4-15 4245-4-15-59D7
4245-4-15 4245-4-15-59F7
现在更复杂的例子(有/涉及)
Parent Child
1090-81
1090-81 1090-81/5285
1090-81/52851090-81/5285-20
1090-81/5285 1090-81/5285-30
1090-81/5285-30 1090-81/5285-30-5
1090-81/5285-30 1090-81/5285-30-5/20
1090-81/5285-30 1090-81/5285-30-6/25
没有确定的最大级别数。我认为我目前看到的最大值是6,但我认为这可能会改变。
答案 0 :(得分:0)
要遵循的一种方法是分层查询。以下查询表示第一个近似值(等待AlexPoole问题的答案):
SELECT DISTINCT *
FROM (
SELECT (SELECT (max(lev)) FROM regextest) - LEVEL lvl
, SUBSTR(item, 1, INSTR(item,'-',-1)-1) parent
, item child
FROM regextest
START WITH lev = (SELECT (max(lev)) FROM regextest)
CONNECT BY PRIOR SUBSTR(item, 1, INSTR(item,'-',-1)- 1) = item
)
WHERE lvl > 0
order by child
;
答案 1 :(得分:0)
既然你说你对正则表达式有一些了解(你甚至将表格命名为regextest),这里有一个使用正则表达式的解决方案 -
SELECT DISTINCT *
FROM ( SELECT PRIOR item AS parentitem, item
FROM regextest
CONNECT BY PRIOR lev = lev - 1
AND REGEXP_SUBSTR (item,
'([0-9A-Z/-]+)([-])([0-9A-Z/]+)',
1,
1,
'i',
1) = PRIOR item)
WHERE parentitem IS NOT NULL
ORDER BY item;
正则表达式拆分'项目'串成3部分:
我确定你可以写一个更干净的正则表达式来做同样的事情。
然后只需将第一个子部分与' PRIOR项目匹配即可。在连接中。匹配的前一项直到最后一个连字符为父项。 可以从第6个参数regex_substr中提取第一个子部分,在本例中为1。
您可以省略
中的connect by子句中的部分PRIOR lev = lev - 1
因为这只是语义而且没有添加任何值。可能更糟糕的是将其保留为该列中的错误数据会使结果陷入混乱。
此外,正如另一个答案指出的那样,Alex Poole的问题仍然存在。为什么示例中的1090-81作为一行不在表中?
答案 2 :(得分:0)
我从我所属的一个小组询问的人提出了以下答案:
SELECT p.item AS parent
, c.item AS child
, c.lev
FROM regextext c
LEFT JOIN regextext p ON p.lev = c.lev - 1
AND REPLACE (c.item, '-', '/' )
LIKE REPLACE (p.item, '-', '/') || '/%';
我花了86分钟来对抗我的真实数据,但结果正是我所寻找的。 p>