Hierachical statement with regular expression

Hi guys,
I was wondering if anyone can help me with the following problem.
Imagine the following tables :
CREATE TABLE organisations
  organ_id number(10),
  parent_id number(10),
  organ_name varchar2(255)
create table renamings
  organ_id number(10),
  search_pattern varchar2(255),
  replace_pattern varchar2(255),
  with_descendants char(1)
INSERT INTO organisations VALUES(0, null, 'Top level');
INSERT INTO organisations VALUES(1, 0, 'A');
INSERT INTO organisations VALUES(11, 1, 'Allo');
INSERT INTO organisations VALUES(2, 0, 'B');
INSERT INTO organisations VALUES(20, 2, 'Battle');
INSERT INTO organisations VALUES(22, 2, 'Star');
INSERT INTO organisations VALUES(299, 2, 'Better');
INSERT INTO organisations VALUES(120, 2, 'Bueno');
INSERT INTO organisations VALUES(3, 0, 'C');
INSERT INTO renamings VALUES(1, 'A', 'X', '0'); -- rename A by X
INSERT INTO renamings VALUES(2, '^B', 'Z', '1'); -- if it starts with B, replace by Z with the descendants.The table organisations contains a hierarchy like an organisational tree. On the renamings table, I have records about the organisations that has to be renamed.
For example, the first record that I inserted in the renamings table means: "Rename the organisation with id = 1. The search patter to apply is 'A' and the replace patter is 'X'. I'd like to use the regexp_replace function to apply the renaming. The latest attribute (0) means that I don't want to rename descendants.
The second record means, rename the organisation with id = 2. The search pattern is '^B' (start with B) and the replace pattern is 'Z'. The last attribute (1) means that the same renaming should be performed on all the descending nodes starting from the organ_id = 2.
The result I would like is:
{code}
ORGAN_ID PARENT_ID ORGAN_NAME
0 Top level
1 0 X
11 1 Allo
2 0 Z
20 2 Zattle
22 2 Star
299 2 Zetter
120 2 Zueno
3 0 C
{code}
I know how to construct the tree, how to rename a specific node using regexp_replace, like this:
{code}
SELECT a.organ_id, a.organ_name, b.search_pattern,
regexp_replace(a.organ_name, b.search_pattern, b.replace_pattern)
FROM organisations a
LEFT JOIN renamings b ON a.organ_id = b.organ_id
START WITH a.organ_id = 0
CONNECT BY PRIOR a.organ_id = a.parent_id;
{code}
But I don't see how I can apply it on all the descending nodes. Any idea?
Thanks,

Hi,
Thanks for posting the CREATE TABLE and INSERT statements; that's very helpful.
Always way which version of Oracle you're using. This is especially important with CONNECT BY queries, because every version since Oracle 7 has had significant changes in this area. Since you want to use REGEXP_REPLACE, I'll assume you're using Oracle 10.1 (or higher).
For each row in organisations, you need to know if a row in renamings matches that row or any of its ancestors. We can use SYS_CONNECT_BY_PATH to get a string containing all of the ancestors' organ_ids, ending with the organ_id of the row itself, and use that to find matching rows in renamings:
WITH     got_ancestor_list     AS
     SELECT     organ_id, parent_id, organ_name
     ,     ROWNUM                              AS rnum
     ,     SYS_CONNECT_BY_PATH (organ_id, ',') || ','     AS ancestor_list
     FROM     organisations
     START WITH     organ_id     = 0
     CONNECT BY     parent_id     = PRIOR organ_id
SELECT       a.organ_id, a.parent_id
,       REGEXP_REPLACE ( a.organ_name
                    , r.search_pattern
                , r.replace_pattern
                )          AS new_organ_name
FROM             got_ancestor_list  a
LEFT OUTER JOIN      renamings         r  ON  a.ancestor_list  LIKE '%,'
                                         ||  r.organ_id
                                         || ','
                                         || CASE
                                                                     WHEN  r.with_descendants = '1'
                                              THEN  '%'
                                                                 END
ORDER BY  a.rnum
;For renamings where with_descendants='0', the join condition evaluates to something like:
ON  a.ancestor_list  LIKE '%,1,'which means the last item in ancestor_list must be 1, and the last item in ancestor_lsit is the organ_id of the row itself.
For renamings where with_descendants='1', the join condition evaluates to something like:
ON  a.ancestor_list  LIKE '%,2,%'(with a '%' at the end) which means some item in ancestor_list must be 2, so the condition applies to organ_id=2 and to all its descendants.
This solution assumes that each row in organisations will match (at most) only one row in renamings. If not, which row from renamings do you want to apply? If all of them, in what order? If this is possible in your application, then post examples in your sample data, results and explanation.
This also assumes that renamings.organ_id is in the tree formed by your START WITH conditions. For example, if you changed the START WITH clause to
START WITH     organ_id     = 120then the row with organ_id=120 would keep the organ_name='Bueno', and not be changed to 'Zueno'. Why? Because, if you start with 120, then 120 has no ancestors; it is not a descendant of any other row, such as the row with organ_id=2, and so the renamings on descendants of organ_id=2 wouldn't apply. If your START WITH condition is
START WITH     parent_id     IS NULLthen there is no problem; all relevant renamings will always apply.
By the way, the CHAR data type is nothing but trouble. Use VARCHAR2 instead. I can hear you saying "The maximum length is 1, so it doesn't matter if iwith_descnedants is CHAR or VARCHAR2." If it doesn't matter, then you shouldn't have any objection to using VARCHAR2. However, if the only possible values are '0' and '1', why not make it NUMBER (1)?

Similar Messages

  • Grouping & Back-references with regular expressions on Replace Text window

    I really appreciate the inclusion of the Regular Expressions in the search & replace feature. One thing I am missing is back-references in the replacement expression. For instance, in the unix tools vi or sed, I might do something like this:
    s/\(firstPart\) \(secondPart\) \(oldThirdPart\)/\2 \1 newThirdPart/g
    which would allow me to switch the places of firstPart and secondPart, and totally replace thirdPart. If grouping and back-references are already present in the Replace Text window, how does one correctly invoke them?

    duplicate of Grouping & Back-references with regular expressions on Replace Text window

  • Assistance with Regular Expression and Tcl

    Assistance with Regular Expression and Tcl
    Hello Everyone,
      I recently began learning Tcl to develop scripts for automating network switch deployments. 
    In my script, I want to name the device with a location and the last three octets of the base mac address.
    I can get the Base MAC address by : 
    show version | include Base
     Base ethernet MAC Address       : 00:00:00:DB:CE:00
    And I can get the last three octets of the MAC address using the following regular expression. 
    ([0-9a-f]{2}[:-]){2}([0-9a-f]{2}$)
    But I have not been able to figure out how to call the regular expression in the tcl script.
    I have checked several resources but have not been able to figure it out.  Suggestions?
    Ultimately, I want to set the last three octets to a variable (something like below) and then call the variable when I name the switch.
    set mac [exec "sh version | i Base"] (include the regular expression)
    ios_config "hostname location$mac"
    Thanks for any assistance in advance.
    Chris

    This worked for me.
    Switch_1(tcl)#set result [exec show ver | inc Base]   
    Base ethernet MAC Address       : 00:1B:D4:F8:B1:80
    Switch_1(tcl)#regexp {([0-9A-F:]{8}\r)} $result -> mac
    1
    Switch_1(tcl)#puts $mac                               
    F8:B1:80
    Switch_1(tcl)#ios_config "hostname location$mac"      
    %Warning! Hostname should contain at least one alphabet or '-' or '_' character
    locationF8:B1:80(tcl)#

  • How to search with regular expression

    I make pdx files so that I can search text quickly. But Acrobat doesn't provide a way to search with regular expression. I'm wondering if there is a way that I don't know to search for regular expression in Acrobat Pro 9?

    First, Acrobat must "mount" the PDX.
    As "Find" does not use the cataloged index, use Shift+Ctrl+F to open the advanced search dialog.
    It may be helpful to first enter Acrobat Preferences and for the Search category tick "Always use advanced search options".
    Back to the Search dialog - use the drop down menu for "Look In" to pick "Select Index" then, if no PDXs show, click the Add button.
    In the Open Index File dialog, browse to the location of the desired PDX and select it.
    OK out and use "Return results containing" to pick a "Match ..." requirement or Boolean.
    To become familiar with query syntax, for Acrobat, it is good to review Acrobat Help.
    http://help.adobe.com/en_US/Acrobat/9.0/Professional/WS58a04a822e3e50102bd615109794195ff-7 c4b.w.html
    Be well...

  • Problem with Regular Expression

    Hi There!!
    I have a problem with regular expression. I want to validate that one word and second word are same. For that I have written a regex
    Pattern p=Pattern.compile("([a-z][a-zA-Z]*)\\s\1");
    Matcher m=p.matcher("nikhil nikhil");
    boolean t=m.matches();
    if (t)
              System.out.println("There is a match");
         else
              System.out.println("There is no match");
    The result I am getting is always "There is no match
    Your timely help will be much appreciated.
    Regards

    Ram wrote:
    ErasP wrote:
    You are missing a backward slash in the regex
    Pattern p = Pattern.compile("([a-z][a-zA-Z]*)\\s\\1");
    But this will fail in this case.
    Matcher m = p.matcher("Nikhil Nikhil");It is the reason for that *[a-z]*.The OP had [a-z][a-zA-Z]* in his code, so presumably he know what that means and wants that String not to match.

  • Get the string between li tags, with regular expression

    I have a unordered list, and I want to store all the strings between the li tags (<li>.?</li>)in an array:
    <ul>
    <li>This is String One</li>
    <li>This is String Two</li>
    <li>This is String Three</li>
    </ul>
    This is what have so far:
    <li>(.*?)</li>
    but it is not correct, I only want the string without the li tags.
    Thanks.

    No one?
    Anoyone here experienced with Regular Expression?

  • Help with Regular Expressions and regexp_replace

    Oh great Oracle Guru can I can gets some help
    I need to clean up the phone numbers that have been entered in Oracle eBusiness per_phones table. Some of the phone numbers have dashes, some have spaces and some have char. I would just like to take all the digits out and then re-format the number.
    Ex.
    914-123-1234 .. output (914) 123-1234
    9141231234 ..again (914) 123-1234
    914 123 1234 .. (914) 123-1234
    myphone ... just null
    (914)-123-1234.. (914) 123-1234
    I really tried to understand the regular expressions statments, but for some reason I just can't understand it.

    Hi,
    Welcome to the forum!
    I would create a user-defined function for this. I expect there will be a lot of exceptions to the regular rules (for example, strings that do not contain exactly 10 digits, such as '1-800-987-6543') that can be handled, but would require lots of nested fucntions and othwer complicted code if you had to do it in a single statement.
    If you really want to do it with a regular expression:
    SELECT     phone_txt
    ,     REGEXP_REPLACE ( phone_txt
                     , '^\D*'          || -- 0 or more non-digits at the beginning of the string
                           '(\d\d\d)'     || -- \1 = 3 consecutive digits
                    '\D*'          || -- 0 or more non-digits
                           '(\d\d\d)'     || -- \2 = 3 consecutive digits
                    '\D*'          || -- 0 or more non-digits
                           '(\d\d\d)'     || -- \3 = 4 consecutive digits
                    '\D*$'             -- 0 or more non-digits at the end of the string
                     , '(\1) \2-\3'
                     )          AS new_phone_txt
    FROM    table_x
    ;

  • Replace replace with regular expression possible?

    Hi,
    Just another regular expression question!
    I want to replace the words "AND", "OR", "NOT" in a sentence with the symbols '&', '|', '~' respectively.
    Obviously very simple to do with 3 replace statements, just wonder if I can use regexp_replace to achieve it?
    Cheers

    Hi,
    Metacharacter symbols can be used in place of regular expressions.
    Here's an implementation scenario:
    http://www.oracle.com/technology/obe/obe10gdb/develop/regexp/regexp.htm
    Hope it helps.
    Regards,
    Naveed.

  • How about the statement of regular expression like for this

    I what to get varians String array by one regular express for the statement like:
    ${user} like play ${game} in ${date}
    I want to get String[] as {"user","game","date"} by one regex, by str.split(regex). I tried many times but always fail to get the result I expected. May it be possible to meet the destination?
    thanks in advance
    Frederick

    why StringBuffer was using here?So one could split the pattern into multiple lines. But it just occurred to me that one could just use string concatenation, which would look better. I don't know why I bothered to use StringBuffefer.
    e.g.:
    String pattern =
        "^" +           // the start of a string
        "(dog)|(cat)" + // match either "dog" or "cat" at the start of the line
        "\\s*" +        // match an arbitrary amount of whitespace
        "$";            // but don't allow anything other than whitespace after dog or cat
    Pattern p = Pattern.compile(pattern);
    Pattern p = Pattern.compile("^(dog)|(cat)\\s*$");> isn't this look more simpler and better?
    In this case, yes. I was looking for a way to make regexps more explicit, with whitespace and comments, for more complicated cases.
    But those double quotes and plus signs add ugliness of their own, so a regexp would have to be pretty complex before it would be an improvement.

  • Replace string with regular expression

    I am new to the regular expression. I am just trying to remove double quotes from a string.
    My sample string is sql statement(SELECT "SCHEMA"."TABLE1"."COLUMN1", "SCHEMA"."TABLE1"."COLUMN2" FROM "SCHEMA"."TABLE1", "SCHEMA"."TABLE2" WHERE "SCHEMA"."TABLE1"."COLUMN1" = "SCHEMA"."TABLE2"."COLUMN1" );
    This is what I came up with.
    String s = query.replaceAll("\\.\"", ".").replaceAll("\"\\.", ".").replaceAll("\\s\"", " ").replaceAll("\\s\"", " ").replaceAll("\",", ",").replaceAll("\"\\s", " ");
    But I want to optimize this line.
    Could anybody tell me how to call replaceAll once with using regular expression instead of calling replaceAll multiple times? Some table or column names can have double quotes, so I want to remove the double quotes without replacing the double quotes which is part of the table or column name.
    I'd appreciated it.

    caesarkim1 wrote:
    I am new to the regular expression. I am just trying to remove double quotes from a string.
    My sample string is sql statement(SELECT "SCHEMA"."TABLE1"."COLUMN1", "SCHEMA"."TABLE1"."COLUMN2" FROM "SCHEMA"."TABLE1", "SCHEMA"."TABLE2" WHERE "SCHEMA"."TABLE1"."COLUMN1" = "SCHEMA"."TABLE2"."COLUMN1" );
    This is what I came up with.
    String s = query.replaceAll("\\.\"", ".").replaceAll("\"\\.", ".").replaceAll("\\s\"", " ").replaceAll("\\s\"", " ").replaceAll("\",", ",").replaceAll("\"\\s", " ");
    ...Note that the following two lines are equivalent:
    s = s.replaceAll("a","").replaceAll("b","");
    s = s.replaceAll("a|b","");

  • Need help with regular expression

    I'm trying to use the java.util.regex package to extract URLs from html files.
    The URLs that I am interested in extracting from the HTML look like the following:
    <font color="#008000">http://forum.java.sun.com -
    So, the URL is always preceeded by:
    <font color="#008000">
    and then followed by a space character and then a hyphen character. I want to be able to put all these URLs in a Vector object. This doesn't seem like it should be too difficult but for some reason I can't get anywhere with it. Any help would be greatly appreciated. Thanks!

    hi gupta am not sure of the java syntax but i can tell u about the regular expression...try this....
    <font color="#008000">(http:\/\/[a-zA-Z0-9.]+) [-]
    i dont know the java methods to call...just the reg exp...
    Sanjay Acharya

  • Help with Regular Expression for field validation

    I'm fairly new to using regular expressions and using Acrobat. This is probably a simple question, but I've been unable to figure it out.
    I have a text field on a PDF that I would like to be 9 characters in length. The first 2 characters can only be alphanumeric, the last 7 characters can only be numeric.
    At first I was using the following, which allows all the characters to be alphanumeric:
    var re = /^[A-Za-z0-9 :\\_]$/;
    if (event.change.length >0) {
    if (event.willCommit == false) {
        if (!re.test(event.change)) {
            event.rc = false
    That works fine, but it's not quite what I needed. With some assistance I changed it (see below) to fit what I was looking for. However, this didn't work; it prevents anything from being entered in the field:
    var re = /^[A-Za-z0-9]{2}\d{7}$/;
    if (event.change.length >0) {
    if (event.willCommit == false) {
        if (!re.test(event.change)) {
            event.rc = false
    Any help would be greatly appreciated.
    Thanks...

    Here's a function you can call form the field's custom Format script. It should be placed in a document-level JavaScript:
    function custom_ks1() {
        // Define non-commited regular expression
        var re = /^[A-Za-z0-9]{0,2}([0-9]{0,7})?$/;
        // Get all of the characters the user has entered
        var value = AFMergeChange(event);
        // Allow field to be cleared
        if(!value) return;
        if (event.willCommit) {
            // Define commited regular expression
            var re = /^[A-Za-z0-9]{2}[0-9]{7}$/;
            if (!re.test(value)) {  // If final value doesn't match, alert user
                app.alert("Your error message goes here.");
                // event.rc = false
        } else {  // not commited
            // Only allow characters that match the regular expression
            event.rc = re.test(value);
    Call it like this:
    // Custom Keystroke script
    custom1_ks();

  • Help with regular expression needed

    Hi,
    Perhaps someone here can help me with my regular expression I'm trying to build in my Java code.
    The regular expression that I'm looking to build consists of any non-whitespace character up until it finds one or two <>= symbols and then any character thereafter. So both these Strings would match the expression:
    City 1==London
    Age>=18
    The regular expression that I'm using is as follows:
    (\\S+)([><=]){1,2}(.+)However, group 1 always retrieves the first <>= symbol as in "City 1=". How can I make the <>= part greedy so that it retrieves both operator symbols?
    Thanks.

    Make the first group, the non-spaces, reluctant:
    "(\\S+?)([<>=]{1,2})(.+)"

  • Help with regular expression to find a pattern in clob

    can someone help me writing a regular expression to query a clob that containts xml type data?
    query to find multiple occurrences of a variable string (i.e <EMPID-XX> - XX can be any number). If <EMPID-01> appears twice in the clob i want the result as EMPID-01,2 and if EMPID-02 appears 4 times i want the result as EMPID-02,4.

    with
    ofx_clob as
    (select q'~
    <EMPID>1
    < UNQID>123456
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>2
    < UNQID>123457
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>1
    < UNQID>123458
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    ~' ofx from dual
    select '<EMPID>' || to_char(ids) || '(' || to_char(count(*)) || ')' multi_empid
      from (select replace(regexp_substr(ofx,'<EMPID>\d*',1,level),'<EMPID>') ids
              from ofx_clob
            connect by level <= regexp_count(ofx,'<EMPID>')
    group by ids having count(*) > 1
    MULTI_EMPID
    <EMPID>1(2)
    with
    ofx_clob as
    (select q'~
    <EMPID>1
    < UNQID>123456
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>2
    < UNQID>123457
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>1
    < UNQID>123456
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>2
    < UNQID>123456
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    <EMPID>1
    < UNQID>123458
    < TIMESTAMP>...
    < ADDRINFO>
    < TITLE>^@~*
    < FIRST>ABCD
    < MI>
    < LAST>EFGH
    < ADDR1>ADDR1
    < ADDR2>^@~*
    < CITY>CITY
    ~' ofx from dual
    select '<EMPID>' || listagg(to_char(ids) || '(' || to_char(count(*)) || ')',',') within group (order by ids) multi_empid
      from (select replace(regexp_substr(ofx,'<EMPID>\d*',1,level),'<EMPID>') ids
              from ofx_clob
            connect by level <= regexp_count(ofx,'<EMPID>')
    group by ids having count(*) > 1
    MULTI_EMPID
    <EMPID>1(3),2(2)
    Regards
    Etbin
    Message was edited by: Etbin
    used listagg to report more than one multiple <EMPID>

  • Help With Regular Expression In Apex Validation

    Apex 3.2
    There is a validation type of regular expression in apex, but I have never used regular expression before,
    so a little help is appreciated.
    I need to validate a field. It is only allowed to contain alpha characers, numbers, spaces and the - (dash) character.
    I have tried several times to get this working
    eg
    [[:alpha:]]*[[:digit:]]*[[:space:]]*[-]*
    ^[[:alpha:][:digit:][:space:]-]+?
    and others, but just can't to get the syntax correct.
    Can someone help me with this please
    Gus

    Example:
    SQL> ed
    Wrote file afiedt.buf
      1  with t as (select 'This is some example text' as txt from dual union all
      2             select 'And this is the 2nd one with numbers' from dual union all
      3             select 'And this allows double-barrelled words with hyphens' from dual union all
      4             select 'But this one shouldn''t be allowed!' from dual
      5            )
      6  --
      7  select *
      8  from t
      9* where regexp_like(txt, '^[[:alnum:] -]*$')
    SQL> /
    TXT
    This is some example text
    And this is the 2nd one with numbers
    And this allows double-barrelled words with hyphens

Maybe you are looking for

  • Sync is grayed out.  Can no longer sync iPod classic with iTunes.

    No longer able to sync iPod classic with iTunes.  The iPod is recognized, but sync is grayed out.  Any help out there?

  • Defining nested table storage for UDT within another UDT

    If I have two types, a FOO UDT which contains a BAR UDT, like this: CREATE TYPE FOO AS OBJECT ( MY_BAR BAR CREATE TYPE BAR AS OBJECT ( A_NESTED_TABLE NESTED_TABLE_TYPE Now when I create a table of FOO, I need to define the storage for the nested tabl

  • YOUR PC CAN'T PROJECT TO ANOTHER SCREENS

    Earlier i have installed a windows 8.1 (32bit) opertiang system then i was able to use another monitor just by using a VGA cable with HDMI connector and it was perfectly working fine. Then i have installed the same OS of 64 bit now even i have instal

  • Lion iCal Can't Open Other Calendars, Outlook Can

    Hey folks - I'm connecting Mail.app, iCal, and Address Book to the corporate Exchange server here at work.  The one bit I can't seem to get to work with any regularity is access other calendars (delegates) in iCal.  I know my NT account can see those

  • How to share ethernet printer via wifi?

    I currently have an ethernet laser printer connected to our two desktops via an ethernet router/hub. If I disconnect the ethernet hard wire from one desktop, is there a way for it to continue to access the printer (ethernet capable, not USB) if I add