Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace multiple tags in a row in select statement from another table

Tags:

sql

oracle

I have two tables.
One is answer_step_dtl
Another is tag_mst as follow

Ans_code                      Ans_Desc
-------------------------------------------
50000000000000005770       Enter <B><APN></B> and press Ok.       
40000000000000000164       Enter <B><ACCOUNTNAME></B> in connection name.
40000000000000000165       Enter <B><ACCOUNTNAME></B> in <APN>.

and so on.

And my tag_mst has values like this

TAG_CODE                    TAG_NAME          TAG_VALUE
-------------------------------------------------------
100                          <APN>            EXAMPLE.COM
101                          <ACCOUNTNAME>    EXAMPLE

Now my requirement is this I want to select answer form answer table with replaced value of tag mast. There can be more than one tag in the one ans_desc.

I was thinking the approach

  1. Loop through the result of answer_dtl fetch the tags from individual record

  2. loop through the multiple tags in the record and then replace the tag

  3. store in a temporary table and then open the cursor for new tem table.

Is this is the approach. Or is there any easy approach of doing this.

like image 646
शेखर Avatar asked Nov 09 '12 07:11

शेखर


2 Answers

Edit: Bonus query using (recursive) CTE, inspired by a note from @Rob van Wijk, needs 11g(R2?):

SQL> WITH data AS (
  2     SELECT ans_code, Ans_Desc, tag_name, tag_value,
  3            row_number() OVER (partition BY ans_code ORDER BY t.rowid) no,
  4            row_number() OVER
  5               (partition BY ans_code ORDER BY t.rowid DESC) is_last
  6        FROM answer_step_dtl a
  7        JOIN tag_mst t ON a.ans_desc LIKE '%' || t.tag_name || '%'
  8  ), n(ans_code, no, is_last, replaced) AS (
  9     SELECT ans_code, no n, is_last,
 10            replace (ans_desc, tag_name, tag_value) replaced
 11       FROM data
 12      WHERE no = 1
 13     UNION ALL
 14     SELECT d.ans_code, d.no, d.is_last,
 15            replace (n.replaced, d.tag_name, d.tag_value) replaced
 16       FROM data d
 17       JOIN n ON d.ans_code = n.ans_code
 18        AND d.no = n.no + 1
 19  )
 20  SELECT *
 21    FROM n
 22   WHERE is_last=1;

ANS_CODE             NO IS_LAST REPLACED
-------------------- -- ------- ---------------------------------------
40000000000000000164  1       1 Enter <B>EXAMPLE</B> in connection
50000000000000005770  1       1 Enter <B>EXAMPLE.COM</B> and press Ok.
40000000000000000165  2       1 Enter <B>EXAMPLE</B> in EXAMPLE.COM.

Initial answer:

You can use of a PL/SQL function. The following will work even if there are several tags to be replaced:

CREATE OR REPLACE FUNCTION replacetags(p_desc VARCHAR2)
   RETURN VARCHAR2 IS
   l_result  LONG := p_desc;
   l_tag_pos INTEGER := 1;
   l_tag     tag_mst.tag_name%TYPE;
BEGIN
   LOOP
      l_tag     := regexp_substr(l_result, '<[^<]+>', l_tag_pos);
      l_tag_pos := regexp_instr(l_result, '<[^<]+>', l_tag_pos) + 1;
      EXIT WHEN l_tag IS NULL;
      BEGIN
         SELECT replace(l_result, l_tag, tag_value)
           INTO l_result
           FROM tag_mst
          WHERE tag_name = l_tag;
      EXCEPTION
         WHEN no_data_found THEN
            NULL; -- tag doesn't exist in tag_mst
      END;
   END LOOP;
   RETURN l_result;
END;

SQL> SELECT ans_code, replacetags(ans_desc)
  2    FROM answer_step_dtl;

ANS_CODE              REPLACETAGS(ANS_DESC)
--------------------- ----------------------------------------
50000000000000005770  Enter <B>EXAMPLE.COM</B> and press Ok.
40000000000000000164  Enter <B>EXAMPLE</B> in connection
40000000000000000165  Enter <B>EXAMPLE</B> in EXAMPLE.COM.
like image 90
Vincent Malgrat Avatar answered Nov 09 '22 20:11

Vincent Malgrat


try this:

select d."Ans_code",replace("Ans_Desc","TAG_NAME","TAG_VALUE")
from   answer_step_dtl d, tag_mst m
where "Ans_Desc" like '%'|| "TAG_NAME" || '%'


SQL fiddle demo

like image 45
Joe G Joseph Avatar answered Nov 09 '22 18:11

Joe G Joseph