Escaping single quote in PLSQL - oracle

I want PLSQL to generate strings like:
COMMENT ON COLUMN TABLE.COLUMN IS 'comment from database';
My solution is:
declare
str_comment varchar2(4000);
begin
for rec in (select table_name, column_name, description from description_table)
loop
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name||' IS '''||rec.description||'''; ' ;
dbms_output.put_line(str_comment);
end loop;
end;
Output is OK when it doesn't contain single qoutes in rec.description. Otherwise there is need for escape letter. How should I implement it?
OK output line (It's has escape letter to preserve single qoute):
COMMENT ON COLUMN TABLE1.COLUMN1_LV IS 'It''s secret';
NOT NOK output line because no escape letter for single quote added and doesn't compile:
COMMENT ON COLUMN TABLE1.COLUMN1_LV IS 'It's secret';
My solution is not to check if description contains single quotes. I just replace source (description) column's single quote by two single quotes before generating COMMENT ON strings and then I ROLLBACK.
Any better solution?

I do this sort stuff a fair bit (usually generating insert/update statements).
You just need to use the replace function to turn all the ' into ''. i.e. Change it to:
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name
||' IS '''||REPLACE( rec.description,'''','''''')||'''; ' ;

You can use the Quote operator like
str_comment:='COMMENT ON COLUMN '||rec.table_name||'.'||rec.column_name||' IS q''[' ||rec.description|| ']'';' ;
see http://psoug.org/reference/string_func.html

Use the REPLACE function in your select.
declare
str_comment varchar2(4000);
begin
for rec in (SELECT table_name, column_name, REPLACE(description, '''', '''''')
FROM description_table)
loop
str_comment:='COMMENT ON COLUMN ' || rec.table_name || '.'
||rec.column_name|| ' IS ''' ||rec.description|| '''; ' ;
dbms_output.put_line(str_comment);
end loop;
end;

You need to use '' in the code
But Before trying it to the actual code ,
try the line which has quotes in the dual
For example:
select '''sumesh''' from dual

Related

Creating tables in procedure in oracle [duplicate]

In the Oracle PL/SQL, how to escape single quote in a string ? I tried this way, it doesn't work.
declare
stmt varchar2(2000);
begin
for i in 1021 .. 6020
loop
stmt := 'insert into MY_TBL (Col) values(\'ER0002\')';
dbms_output.put_line(stmt);
execute immediate stmt;
commit;
end loop;
exception
when others then
rollback;
dbms_output.put_line(sqlerrm);
end;
/
You can use literal quoting:
stmt := q'[insert into MY_TBL (Col) values('ER0002')]';
Documentation for literals can be found here.
Alternatively, you can use two quotes to denote a single quote:
stmt := 'insert into MY_TBL (Col) values(''ER0002'')';
The literal quoting mechanism with the Q syntax is more flexible and readable, IMO.
Here's a blog post that should help with escaping ticks in strings.
Here's the simplest method from said post:
The most simple and most used way is to use a single quotation mark with two single quotation marks in both sides.
SELECT 'test single quote''' from dual;
The output of the above statement would be:
test single quote'
Simply stating you require an additional single quote character to print a single quote character. That is if you put two single quote characters Oracle will print one. The first one acts like an escape character.
This is the simplest way to print single quotation marks in Oracle. But it will get complex when you have to print a set of quotation marks instead of just one. In this situation the following method works fine. But it requires some more typing labour.
In addition to DCookie's answer above, you can also use chr(39) for a single quote.
I find this particularly useful when I have to create a number of insert/update statements based on a large amount of existing data.
Here's a very quick example:
Lets say we have a very simple table, Customers, that has 2 columns, FirstName and LastName. We need to move the data into Customers2, so we need to generate a bunch of INSERT statements.
Select 'INSERT INTO Customers2 (FirstName, LastName) ' ||
'VALUES (' || chr(39) || FirstName || chr(39) ',' ||
chr(39) || LastName || chr(39) || ');' From Customers;
I've found this to be very useful when moving data from one environment to another, or when rebuilding an environment quickly.
In my case, I use like this:
stmt := q'!insert into MY_TBL (Col) values('ER0002')!';
Adding: q'! before and !' after string.
This is another reference: Alternative Quoting Mechanism (''Q'') for String Literals
EXECUTE IMMEDIATE 'insert into MY_TBL (Col) values(''ER0002'')'; worked for me.
closing the varchar/string with two pairs of single quotes did the trick. Other option could be to use using keyword, EXECUTE IMMEDIATE 'insert into MY_TBL (Col) values(:text_string)' using 'ER0002'; Remember using keyword will not work, if you are using EXECUTE IMMEDIATE to execute DDL's with parameters, however, using quotes will work for DDL's.

Oracle PL/SQL - wildcard replacements with empty strings

To give you a little heads up. I am fairly new to the PL/SQL world.
Most of the text below is just to give you a little context.
Also, I have to use a function to generate the text on the fly. It is not an option to write the text into the db.
Anyway, I am working on a set of functions that will generate strings.
function f_nlg_concat(p_id in number) return varchar2 as
l_id number;
l_text_schaden varchar2(4000);
begin
l_id := p_id;
l_text := f_nlg(l_id);
l_text := f_nlg_replace(l_text, l_id);
end;
The above function is the one that concatinates all the strings. For this example I will only use one text (l_text). The l_text will be provided by the function:
f_nlg(p_id)
Now where it gets interesting is the second function:
f_nlg_replace(p_text,p_id)
This function basically queries via dynamic sql to find the right replacements for the wildcard. There are alot of wildcards.
A text might look like:
'I am a text with this <wildcard>.'
A view provides the right wildcard replacement. I am able to identify the right replacement by iterating over all the columns of the view by using this dynamic sql:
for cur in (SELECT atc.column_name
FROM all_tab_cols atc
WHERE lower(table_name) like 'v_nlg_wildcards'
AND owner = 'ME') loop
/*check if exist*/
l_query1 := 'select count(' || cur.column_name ||
') from ME.v_nlg_wildcards nw where nw.id =' ||
l_id;
execute immediate l_query1
into l_wildcard;
if l_wildcard = 1 then
l_query2 := 'select ' || cur.column_name ||
' from ME.v_nlg_wildcard nw where nw.id =' ||
l_id;
execute immediate l_query2
into l_baustein;
/*THIS IS WHERE I GOT A QUESTION*/
l_text := replace(l_text,
'<' || lower(cur.column_name) || '>',
l_wildcard);
else
continue;
end if;
end loop;
It works all perfect as long as there are wildcards to find. I case there is a NULL the replace wont work obviously.
But have you had any familiar cases in where you had to replace wildcards with empty strings?
Any ideas on how to still do the replacements?
So that there'll be no wildcards left in the text.
The whole text should still look like there is not wildcard left. The sentences are partly written that an empty replacement would fit as well.
Thank y'all in advance.
Cheers,
Sven

How to handle dynamic variable string value in single line

This is my PL/SQL block. When i execute it the result of 'V_QUERY' variable breaks into two lines like:
'%[CDATA[/documents/%/4min.png
/%'.
How can i get it in one line like below: enter image description here
'%[CDATA[/documents/%/4min.png/%'
.
declare
cursor c1 is
select rtrim(ltrim(substr(typesettings, 7), '"'), '"') as typesettings
from trashentry
where rownum < 2;
v_query varchar2(32767);
begin
for r1 in c1
loop
v_query := '''%[CDATA[/documents/%/' || r1.typesettings || '/%''';
dbms_output.put_line(v_query);
end loop;
end;
Most likely you need to trim chr(10) from the end of typesettings. It may not hurt to trim chr(13) as well, on the chance it may be present too.
Assuming there aren't any double-quotes in your input string that you need to keep, you can achieve several things at once: Instead of rtrim(ltrim(...)) (which should be a trim(...) anyway, it does the same thing and is simpler and only calls one function instead of two), you could use translate:
select translate(substr(typesettings, 7), 'x"' || chr(10) || chr(13), 'x') as typesettings
.......
Notice the x in the last two parameters; it doesn't really do anything, it just works around a limitation of the translate function (which in turn is due to Oracle's treatment of empty strings as NULL). In this example, translate will replace every x in the input string with x, and every occurrence of ", chr(10) and chr(13) will be simply deleted.

PL/SQL, how to escape single quote in a string?

In the Oracle PL/SQL, how to escape single quote in a string ? I tried this way, it doesn't work.
declare
stmt varchar2(2000);
begin
for i in 1021 .. 6020
loop
stmt := 'insert into MY_TBL (Col) values(\'ER0002\')';
dbms_output.put_line(stmt);
execute immediate stmt;
commit;
end loop;
exception
when others then
rollback;
dbms_output.put_line(sqlerrm);
end;
/
You can use literal quoting:
stmt := q'[insert into MY_TBL (Col) values('ER0002')]';
Documentation for literals can be found here.
Alternatively, you can use two quotes to denote a single quote:
stmt := 'insert into MY_TBL (Col) values(''ER0002'')';
The literal quoting mechanism with the Q syntax is more flexible and readable, IMO.
Here's a blog post that should help with escaping ticks in strings.
Here's the simplest method from said post:
The most simple and most used way is to use a single quotation mark with two single quotation marks in both sides.
SELECT 'test single quote''' from dual;
The output of the above statement would be:
test single quote'
Simply stating you require an additional single quote character to print a single quote character. That is if you put two single quote characters Oracle will print one. The first one acts like an escape character.
This is the simplest way to print single quotation marks in Oracle. But it will get complex when you have to print a set of quotation marks instead of just one. In this situation the following method works fine. But it requires some more typing labour.
In addition to DCookie's answer above, you can also use chr(39) for a single quote.
I find this particularly useful when I have to create a number of insert/update statements based on a large amount of existing data.
Here's a very quick example:
Lets say we have a very simple table, Customers, that has 2 columns, FirstName and LastName. We need to move the data into Customers2, so we need to generate a bunch of INSERT statements.
Select 'INSERT INTO Customers2 (FirstName, LastName) ' ||
'VALUES (' || chr(39) || FirstName || chr(39) ',' ||
chr(39) || LastName || chr(39) || ');' From Customers;
I've found this to be very useful when moving data from one environment to another, or when rebuilding an environment quickly.
In my case, I use like this:
stmt := q'!insert into MY_TBL (Col) values('ER0002')!';
Adding: q'! before and !' after string.
This is another reference: Alternative Quoting Mechanism (''Q'') for String Literals
EXECUTE IMMEDIATE 'insert into MY_TBL (Col) values(''ER0002'')'; worked for me.
closing the varchar/string with two pairs of single quotes did the trick. Other option could be to use using keyword, EXECUTE IMMEDIATE 'insert into MY_TBL (Col) values(:text_string)' using 'ER0002'; Remember using keyword will not work, if you are using EXECUTE IMMEDIATE to execute DDL's with parameters, however, using quotes will work for DDL's.

Oracle: Convert xml entities in a varchar2 field to utf-8 characters

I have a field in a table which holds XML entities for special characters, since the table is in latin-1.
E.g. "Hallöle slovenčina" (the "ö" is in latin-1, but the "č" in "slovenčina" had to be converted to an entity by some application that stores the values into the database)
Now I need to export the table into a utf-8 encoded file by converting the XML entities to their original characters.
Is there a function in Oracle that might handle this for me, or do I really need to create a huge key/value map for that?
Any help is greatly appreciated.
EDIT: I found the function DBMS_XMLGEN.convert, but it only works on <,> and &. Not on &#NNN; :-(
I believe the problem with dbms_xmlgen is that there are technically only five XML entities. Your example has a numeric HTML entity, which corresponds with Unicode:
http://theorem.ca/~mvcorks/cgi-bin/unicode.pl.cgi?start=0100&end=017F
Oracle has a function UNISTR which is helpful here:
select unistr('sloven\010dina') from dual;
I've converted 269 to its hex equivalent 010d in the example above (in Unicode it is U+010D). However, you could pass a decimal number and do a conversion like this:
select unistr('sloven\' || replace(to_char(269, 'xxx'), ' ', '0') || 'ina') from dual;
EDIT: The PL/SQL solution:
Here's an example I've rigged up for you. This should loop over and replace any occurrences for each row you select out of your table(s).
create table html_entities (
id NUMBER(3),
text_row VARCHAR2(100)
);
INSERT INTO html_entities
VALUES (1, 'Hallöle slovenčina Ċ ú');
INSERT INTO html_entities
VALUES (2, 'I like the letter Ċ');
INSERT INTO html_entities
VALUES (3, 'Nothing to change here.');
DECLARE
v_replace_str NVARCHAR2(1000);
v_fh UTL_FILE.FILE_TYPE;
BEGIN
--v_fh := utl_file.fopen_nchar(LOCATION IN VARCHAR2, FILENAME IN VARCHAR2, OPEN_MODE IN VARCHAR2, MAX_LINESIZE IN BINARY_INTEGER);
FOR v_rec IN (select id, text_row from html_entities) LOOP
v_replace_str := v_rec.text_row;
WHILE (REGEXP_INSTR(v_replace_str, '&#[0-9]+;') <> 0) LOOP
v_replace_str := REGEXP_REPLACE(
v_replace_str,
'&#([0-9]+);',
unistr('\' || replace(to_char(to_number(regexp_replace(v_replace_str, '.*?&#([0-9]+);.*$', '\1')), 'xxx'), ' ', '0')),
1,
1
);
END LOOP;
-- utl_file.put_line_nchar(v_fh, v_replace_str);
dbms_output.put_line(v_replace_str);
END LOOP;
--utl_file.fclose(v_fh);
END;
/
Notice that I've stubbed in calls to the UTL_FILE function to write NVARCHAR lines (Oracle's extended character set) to a file on the database server. The dbms_output, while great for debugging, doesn't seem to support extended characters, but this shouldn't be a problem if you use UTL_FILE to write to a file. Here's the DBMS_OUTPUT:
Hallöle slovencina C ú
I like the letter C
Nothing to change here.
You can also just use the internationalization package :
UTL_I18N.unescape_reference ('text')
Works great in changing those html entities to normal characters (such as cleanup after moving a database from iso 8859P1 to UTF-8)
This should probably be done in PL/SQL which I do not know, but I wanted to see how far I could get it with pure SQL. This only replaces the first occurence of the code, so you would have to somehow run it multiple times.
select regexp_replace(s, '&#([0-9]+);', u) from
(select s, unistr('\0' || REPLACE(TO_CHAR(TO_NUMBER(c), 'xxxx'), ' ', '')) u from
(select s, regexp_replace(s, '.*&#([0-9]+);.*', '\1') c from
(select 'Hallöle slovenčina' s from dual)))
Or less readable but more usable:
SELECT
REGEXP_REPLACE(s, '&#([0-9]+);', unistr('\0' || REPLACE(TO_CHAR(TO_NUMBER(regexp_replace(s, '.*?&#([0-9]+);.*$', '\1', 1, 1)), 'xxxx'), ' ', '')), 1, 1)
FROM
(SELECT 'Hallöle slovenčina č Ė' s FROM DUAL)
This (updated) version correctly replaces the first occurrence. You need to apply it until all of them are replaced.

Resources