I must Update Oracle database with remove part of string, problem is that this part can be in multiple place in this string. Example:
I must remove part and Update database where clolumn_name like ('%,aaa%') from
'bbb,aaa,ccc,ddd' or 'bbb,ccc,aaa,ddd' or from 'bbb,ccc,eee,fff,aaa,ddd'
Please help me :)
To replace complete terms using simple string functions (which is much quicker than regular expressions) is:
SELECT TRIM(
BOTH ',' FROM
REPLACE(','||value||',', ',aaa,', ',')
) AS replaced_value
FROM table_name
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT 'aaa' FROM DUAL UNION ALL
SELECT 'aaa,bbb' FROM DUAL UNION ALL
SELECT 'ccc,aaa' FROM DUAL UNION ALL
SELECT 'ddd,aaa,eee' FROM DUAL UNION ALL
SELECT 'fff,aaa,ggg,aaa,hhh' FROM DUAL UNION ALL
SELECT 'aaa,aaa,aaa' FROM DUAL;
Outputs:
REPLACED_VALUE
null
bbb
ccc
ddd,eee
fff,ggg,hhh
aaa
Note: if you can have multiple sequential terms, as per the last example, then using simple string functions will not work; but in other cases when ther are non-sequential repeated terms it will work.
If you can have multiple sequential repeated terms then you can use REGEXP_REPLACE:
SELECT TRIM(
BOTH ',' FROM
REGEXP_REPLACE(','||value||',', '(,aaa)+,', ',')
) AS replaced_value
FROM table_name
Which outputs:
REPLACED_VALUE
null
bbb
ccc
ddd,eee
fff,ggg,hhh
null
fiddle
As for your comment:
I must update database where column_name like ('%,aaa%,)
If you want to remove aaa from the start of each term (and remove empty terms) then:
UPDATE table_name
SET value = TRIM(
BOTH ',' FROM
REGEXP_REPLACE(
REGEXP_REPLACE(value, '(^|,)aaa', '\1'),
',{2,}',
','
)
)
WHERE value LIKE '%,aaa%'
OR value LIKE 'aaa%'
fiddle
You may use a regex replacement approach here:
SELECT val, TRIM(BOTH ',' FROM REGEXP_REPLACE(val, 'aaa,|,aaa,|,aaa', ',')) AS val_out
FROM yourTable;
Demo
If you require an update, then use:
UPDATE yourTable
SET val = TRIM(BOTH ',' FROM REGEXP_REPLACE(val, 'aaa,|,aaa,|,aaa', ','))
WHERE ',' || val || ',' LIKE '%,aaa,%';
Related
Using Oracle 11g
select regexp_replace('aaa_bbb', '(_.)', upper('\1')) from dual;
I want 'aaa_Bbb'.
But, it returns 'aaa_bbb'.
Why can't replace?
Upper execute earlier Regexp
select regexp_replace('aaa_bbb', '(_.)', upper(regexp_substr('aaa_bbb', '(_.)'))) from dual
The problem with
select regexp_replace('aaa_bbb', '(_.)', upper('\1')) from dual;
is that upper is executed before regexp_replace, effectively making it:
select regexp_replace('aaa_bbb', '(_.)', '\1') from dual;
So you need a different approach.
See the answer to oracle regexp replace uppercase replacement string
If it doesn't have to be regular expressions approach, then substr + instr + initcap might help.
SQL> with test (col) as
2 (select 'aaa_bbb' from dual)
3 select substr(col, 1, instr(col, '_')) || initcap(substr(col, instr(col, '_') + 1)) result
4 from test;
RESULT
-------
aaa_Bbb
SQL>
I don't think there's a direct method to convert by using regexp_replace but it's possible by regexp_substr in such a way :
with t(str) as
(
select 'aaa_bbb' from dual
)
select concat( regexp_substr(str, '.*[_^]'), initcap( regexp_substr(str, '[^_]+$') ) )
as "Formatted String"
from t;
Formatted String
----------------
aaa_Bbb
Demo
I want to make an array and put into it two id's, but I got a mistake:
array value must start with “{” or dimension information
ids_list character varying[] := ' || (SELECT COALESCE(quote_literal((array_agg(DISTINCT house_guid)) || ''',''' || quote_literal(array_agg(DISTINCT guid))), 'NULL') FROM tb) || ';
use array_agg function
with t1 as
(
select * from
(
select 'test_SQL_01' as ID
union
select 'test_SQL_02_PQR_01'
union
select 'test_SQL_03_055'
union
select 'test_SQL_04_ABC_99'
) as t
) select array_agg(ID) from t1
You seem to be using this inside a PL/pgSQL function. You should be using SELECT ... INTO variable FROM... instead:
declare
ids_list character varying[];
begin
.....
select array_agg(id)
into ids_list
from (
select house_guid
from tab
union
select guid
from tab
) t;
.... work with the ids_list variable
end;
The UNION will automatically remove all duplicates (as you tried to do with DISTINCT.
I have a column that contains data that I want to escape in order to use it as JSON output, to be more precise am trying to escape the same characters listed here but using Oracle 11g: Special Characters and JSON Escaping Rules
I think it can be solved using REGEXP_REPLACE:
SELECT REGEXP_REPLACE(my_column, '("|\\|/)|(' || CHR(9) || ')', '\\\1') FROM my_table;
But I am lost about replacing the other characters (tab, new line, backspace, etc), in the previous example I know that \1 will match and replace the first group but I am not sure how to capture the tab in the second group and then replace it with \t. Somebody could give me a hint about how to do the replacement?
I know I can do this:
SELECT REGEXP_REPLACE( REGEXP_REPLACE(my_column, '("|\\|/)', '\\\1'), '(' || CHR(9) || ')', '\t')
FROM my_table;
But I would have to nest like 5 calls to REGEXP_REPLACE, and I suspect I should be able to do it in just one or two calls.
I am aware about other packages or libraries for JSON but I think this case is simple enough that it can be solved with the functions that Oracle offers out-of-the-box.
Thank you.
Here's a start. Replacing all the regular characters is easy enough, it's the control characters that will be tricky. This method uses a group consisting of a character class that contains the characters you want to add the backslash in front of. Note that characters inside of the class do not need to be escaped. The argument to REGEXP_REPLACE of 1 means start at the first position and the 0 means to replace all occurrences found in the source string.
SELECT REGEXP_REPLACE('t/h"is"'||chr(9)||'is a|te\st', '([/\|"])', '\\\1', 1, 0) FROM dual;
Replacing the TAB and a carriage return is easy enough by wrapping the above in REPLACE calls, but it stinks to have to do this for each control character. Thus, I'm afraid my answer isn't really a full answer for you, it only helps you with the regular characters a bit:
SQL> SELECT REPLACE(REPLACE(REGEXP_REPLACE('t/h"is"'||chr(9)||'is
2 a|te\st', '([/\|"])', '\\\1', 1, 0), chr(9), '\t'), chr(10), '\n') fixe
3 FROM dual;
FIXED
-------------------------
t\/h\"is\"\tis\na\|te\\st
SQL>
EDIT: Here's a solution! I don't claim to understand it fully, but basically it creates a translation table that joins to your string (in the inp_str table). The connect by, level traverses the length of the string and replaces characters where there is a match in the translation table. I modified a solution found here: http://database.developer-works.com/article/14901746/Replace+%28translate%29+one+char+to+many that really doesn't have a great explanation. Hopefully someone here will chime in and explain this fully.
SQL> with trans_tbl(ch_frm, str_to) as (
select '"', '\"' from dual union
select '/', '\/' from dual union
select '\', '\\' from dual union
select chr(8), '\b' from dual union -- BS
select chr(12), '\f' from dual union -- FF
select chr(10), '\n' from dual union -- NL
select chr(13), '\r' from dual union -- CR
select chr(9), '\t' from dual -- HT
),
inp_str as (
select 'No' || chr(12) || 'w is ' || chr(9) || 'the "time" for /all go\od men to '||
chr(8)||'com' || chr(10) || 'e to the aid of their ' || chr(13) || 'country' txt from dual
)
select max(replace(sys_connect_by_path(ch,'`'),'`')) as txt
from (
select lvl
,decode(str_to,null,substr(txt, lvl, 1),str_to) as ch
from inp_str cross join (select level lvl from inp_str connect by level <= length(txt))
left outer join trans_tbl on (ch_frm = substr(txt, lvl, 1))
)
connect by lvl = prior lvl+1
start with lvl = 1;
TXT
------------------------------------------------------------------------------------------
No\fw is \tthe \"time\" for \/all go\\od men to \bcom\ne to the aid of their \rcountry
SQL>
EDIT 8/10/2016 - Make it a function for encapsulation and reusability so you could use it for multiple columns at once:
create or replace function esc_json(string_in varchar2)
return varchar2
is
s_converted varchar2(4000);
BEGIN
with trans_tbl(ch_frm, str_to) as (
select '"', '\"' from dual union
select '/', '\/' from dual union
select '\', '\\' from dual union
select chr(8), '\b' from dual union -- BS
select chr(12), '\f' from dual union -- FF
select chr(10), '\n' from dual union -- NL
select chr(13), '\r' from dual union -- CR
select chr(9), '\t' from dual -- HT
),
inp_str(txt) as (
select string_in from dual
)
select max(replace(sys_connect_by_path(ch,'`'),'`')) as c_text
into s_converted
from (
select lvl
,decode(str_to,null,substr(txt, lvl, 1),str_to) as ch
from inp_str cross join (select level lvl from inp_str connect by level <= length(txt))
left outer join trans_tbl on (ch_frm = substr(txt, lvl, 1))
)
connect by lvl = prior lvl+1
start with lvl = 1;
return s_converted;
end esc_json;
Example to call for multiple columns at once:
select esc_json(column_1), esc_json(column_2)
from your_table;
Inspired by the answer above, I created this simpler "one-liner" function:
create or replace function json_esc (
str IN varchar2
) return varchar2
begin
return REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(str, chr(8), '\b'), chr(9), '\t'), chr(10), '\n'), chr(12), '\f'), chr(13), '\r');
end;
Please note, both this and #Gary_W's answer above are not escaping all control characters as the json.org seems to indicate.
in sql server you can use STRING_ESCAPE() function like below:
SELECT
STRING_ESCAPE('['' This is a special / "message" /'']', 'json') AS
escapedJson;
I am trying to find a match with a given list of search parameters appearing anywhere in the given string. The search parameters can be OR or AND. REGEXP_LIKE with REPLACE works fine with OR (|) but not able to do for AND. Here is an example of OR:
select 'match' from dual WHERE REGEXP_LIKE('BCR081', REPLACE ('BCR;081', ';', '|')); --works
select 'match' from dual WHERE REGEXP_LIKE('BCR081', '(' || REPLACE ('BCR;081', ';', ').*?(') || ')');
-- Works when they are in order but order shouldn't matter.
select 'match' from dual WHERE REGEXP_LIKE('BCR081', '(' || REPLACE ('081;BCR', ';', ').*?(') || ')'); --I need this to work.
Is there something equivalent to
select 'match' from dual WHERE REGEXP_LIKE('BCR081', REPLACE ('BCR;081', ';', '&'));
Any help is greatly appreciated. I tried (look ahead?):
select 'match' from dual WHERE REGEXP_LIKE('BCR081','(?=' || REPLACE ('081;BCR', ';', ')(?=') || ')');
Note: The above is an example only, we can have anywhere from 1-20 search parameters. Also can't use the contains clause as it will throw too many results error.
We can tokenise the search string and look for one by one, by virtually generating rows.
with my_data as
(
select 'BCR081' as str , 'BCR;081' as pattern from dual
),
pattern_table as
(
select str, regexp_substr(pattern,'[^;]+',1,level) as pattern
from my_data
connect by level <= regexp_count(pattern,';') + 1
)
SELECT DECODE(
COUNT(DECODE(
INSTR(a.str,b.pattern),
0,
null,
1)
),
0,
'no match',
'match'
) as result
FROM my_data a, pattern_table b
WHERE a.str = b.str
GROUP BY a.str;
Suppose I have a string '1,2,3'
I want to tokenize the string and convert each of the tokens into NUMBER. So the above string will be tokenized into :
1 NUMBER
2 NUMBER
3 NUMBER
The final intention is to use them in a query as part of IN clause as below :
select * from sample where type in (1,2,3) ;
How can I achieve this ? One important point here is the string can have different number of tokens in different situations. So it can be either '1,2,3' or '1,2' or '1,2,3,4' or even '1'.
Please help me out guys.
Thanks in advance.
Please try:
with test as
(
select '1,2,3' str from dual
)
select * from sample
where type in(
select regexp_substr (str, '[^,]+', 1, rownum) split
from test
connect by level <= length (regexp_replace (str, '[^,]+')) + 1);
Depending on what you are doing, it might be faster to convert the id to a String and look for it in your String. Just add a comma to the beginning and the end of your list.
SELECT id
FROM (SELECT 1 AS id FROM DUAL
UNION
SELECT 2 FROM DUAL
UNION
SELECT 3 FROM DUAL) idtable
WHERE ',' || '1,3,4,5' || ',' LIKE '%,' || idtable.id || ',%'