I had a file that I was processing and it was constantly giving me errors. After some checking I realized that it had some special characters that were hidden.
I have just manually found the hidden characters and made a simple replace like
REPLACE( String,'', '')
How could I prevent this from happening in the future?
I have tried to make a table that stores these hidden ascii characters which are in the range from 125-255 but the database does not store them accordingly.
For example chr(168) is not the same as ascii 168.
select chr('168'),
convert(chr('168'),
'US7ASCII',
'WE8ISO8859P1')
from dual;
What else can I try?
Easy to write, but not the fastest to execute - using regexp_replace:
update table_name
set column_name =
regexp_replace(column_name, '[' || chr(125) || '-' || chr(255) || ']', '')
;
More efficient, but a pain in the neck to write and maintain (you can write some code to generate the code though, to save some typing):
...
set column_name =
translate(column_name, '~' || chr(125) || chr(126) || ..... || chr(255), '~')
;
Yes, with translate() you will have to spell them all out, no "range" concept... {:-(
That's to change the data already in the tables. It would be even better to fix the data as it is coming in, if you can - using a similar transformation.
Related
I am trying to create and execute a dynamic SQL statement (using Oracle PL/SQL) and when things didn't work I condensed it to the below two code snippets:
My understanding was that the following two statements would be equivalent (table_name, row_name and row_value are all VARCHAR2 strings):
query_statement VARCHAR2(1000);
-- variant a:
query_statement := 'select * from ' || table_name || ' where ' || row_name || ' = ' || row_value;
dbms_output.put_line('query="' || query_statement || '"');
execute immediate (query_statement);
-- variant b:
query_statement := 'select * from :table where :row = :value';
dbms_output.put_line('query="' || query_statement || '"');
execute immediate (query_statement) using table_name, row_name, row_value;
But not so! The first variant works fine, the second always fails with an error:
** An error was encountered: -903 ORA-00903: invalid table name
From a readability point of view I would prefer variant b but I don't get, why that second variant fails and why the table_name is flagged as wrong. After all that very same name obviously works in variant a. The emitted queries also looks identical to me - of course modulo the fact that the second string still contains placeholders only while the first string contains already concrete values.
Could some kind soul shed some light on this? Why is variant b not working? What am I missing?
As mentioned by #William, usage of bind variable as Tablename is prohibited. On similar lines, you cannot use bind variables as Column Names and Order By clause as well.
Although this is not documented anywhere but its important to note that replacing these ordinal notation affects the execution plan.
You can't use a bind variable as a table_reference. As documented in the link, the table_reference must be static part of the statement.
select * from :table -- ILLEGAL
Contrary to that the usage in the WHERE clause is allowed
where :row = :value -- LEGAL, but questionable
but it doesn't do what you expect. The whereclause returns TRUE, if both bind variables passed are same.
I.e. it is equivalent to
where 'name' = 'xxxx'
and not to
where name = 'xxxx'
I've come across this in one of the sql scripts we have for one of our apps. I notice that it's used in various other places, but isn't it just checking for an existence of an item?
AND INSTR((SELECT (',' || REPLACE('OWN, JO', ' ', NULL) || ',') b FROM DUAL),
(',' || aao.AcctRoleCd || ',')) > 0
Where it's looking to see if 'OWN' or 'JO' is in aao.AcctRoleCd. If it is then INSTR would result in its index in the string, so it'll be greater than one. So the AND clause would be true.
Isn't this poor to check if an item exists like this? Would something more of the lines of an IN clause be better?
AND aao.AcctRoleCd IN ('OWN', 'JO');
Almost:
'OWN, JO' is a text literal.
REPLACE('OWN, JO', ' ', NULL) just strips the space from the string giving 'OWN,JO'.
',' || 'OWN,JO' || ',' just concatenates commas to the start and end of the string giving ',OWN,JO,'.
(SELECT ',OWN,JO,') b FROM DUAL) is redundant and you can just use the previous text literal.
INSTR( ',OWN,JO,', (',' || aao.AcctRoleCd || ',') ) > 0 is looking for a comma at the start and end of the substring which equals aao.AcctRoleCd so could match either 'OWN', 'JO' or 'OWN,JO'.
So you can replace it with:
AND aao.AcctRoleCd IN ( 'OWN', 'JO', 'OWN,JO' )
Now, it may be that 'OWN,JO' is not a match you are expecting (or may not even be a valid value) and you can strip it from the list but that is something you will need to determine.
You are right, but thanks for sharing that surprisingly bad code.
(SELECT (',' || REPLACE('OWN, JO', ' ', NULL) || ',') b FROM DUAL)
is a completely unnecessary scalar subquery. It could be replaced by
',' || REPLACE('OWN, JO', ' ', NULL) || ','
However, since that snippet has only literals then it could be further replaced by the result:
,OWN,JO,
and yes, it would seem that whole INSTR could be replaced by the code you suggest, unless aao.AcctRoleCd could contain 'N,J' or some such in which case the original code and your code would get different results. I seriously doubt that is a problem.
Best regards, Stew
i am trying to insert data into one of my table.
insert into t_transaction_query_log
(log_id,
posting_id,
fee_id,
fee_status,
fee_type,
pay_mode,
accounting_date,
policy_id,
money_id,
finish_time,
source_type,
fee_amount,
cr_seg,
dr_seg,
product_id' || v_insert_str_cr_seg ||
v_insert_str_dr_seg || ')
select s_transaction_query_log__lg_id.nextval,
tg.je_posting_id,
tg.fee_id,
tg.fee_status,
tg.fee_type,
60,
tg.accounting_date,
tg.policy_id,
tg.currency_id,
trunc(sysdate,
''dd''),
2,
tg.fee_amount,' ||v_str_cr_seg
|| ',' || v_str_dr_seg || ',
tg.product_id' || v_insert_str_cr_seg ||
v_insert_str_dr_seg || '
from t_ri_fee_gl tg
where tg.posted = ''Y''
i have declared v_str_cr_seg,v_str_dr_seg as empty strings i.e v_str_dr_seg varchar(50)='';
before executing this query i am able to append some values to these two strings
but in case there is no change in these strings from the declaration
i am getting the computed query as
insert into t_transaction_query_log
(log_id,
posting_id,
fee_id,
fee_status,
fee_type,
pay_mode,
accounting_date,
policy_id,
money_id,
finish_time,
source_type,
fee_amount,
cr_seg,
dr_seg,
product_id)
select s_transaction_query_log__lg_id.nextval,
tg.je_posting_id,
tg.fee_id,
tg.fee_status,
tg.fee_type,
60,
tg.accounting_date,
tg.policy_id,
tg.currency_id,
trunc(sysdate,
'dd'),
2,
tg.fee_amount, , ,
tg.product_id
from t_ri_fee_gl tg
where tg.posted = 'Y'
which in turn results in missing expression error.
i have tried using nvl function as
nvl(v_str_cr_seg, '') and `nvl(v_str_cr_seg, null)`
but still i am getting the same error
how can i insert even though v_str_cr_seg and v_str_dr_seg are unchanged
i.e empty strings ''
Ora DB:
empty string = null
enter link description here
Note:
Oracle Database currently treats a character value with a length of zero as null. However, this may not continue to be true in future releases, and Oracle recommends that you do not treat empty strings the same as nulls.
If this is an insert Statement in the middle of a PL/SQL Routine, then you would not string concatenate. It would rather look like this
tg.fee_amount, v_str_cr_seg, v_str_dr_seg
But something from your question tells me that you are composing a string that you want to execute immediate.
In this case you have to make sure you are giving quotes:
tg.fee_amount,''' ||v_str_cr_seg
|| ''',''' || v_str_dr_seg || ''',
tg.product_id''' || v_insert_str_cr_seg ||
v_insert_str_dr_seg || '''
You need to escape the single quote (') with two quotes in a row ('')
But if your strings already come with quotes around it unless null you may want to work with nvl this way
tg.fee_amount,' ||nvl(v_str_cr_seg,'''''')
|| ',' || nvl(v_str_dr_seg,'''''') || ',
Try using chr(0) instead of ''. Null character is a sign of the end of a string.
I'm trying to all rows where a column contains any control charters with the exception of the line feed character (hex value of A). I've tried the following, but this only returns results that have a control character and don't have a line feed. I really want the set of characters that are control characters, LESS the line feed character. Is there a 'minus' operation for character sets, where you can exclude particular ones from it?
SELECT *
FROM MyTable
WHERE REGEXP_LIKE(MyColumn, '[:cntrl: &&[^' || UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('A')) || ']]{1,}');
Any thoughts?
Thanks!
Well here's a first try that will work but I'm sure this can be made more elegant and efficient:
SELECT *
FROM MyTable
WHERE regexp_like(MyColumn, '[[:cntrl:]]')
AND MyColumn NOT like '%' || chr(10) || '%';
I would like to programmatically export my Procedures / Functions and Packages into individual files (as a backup) and using Oracle 9.2.
The closest solution i found was using DBMS_METADATA.GET_DDL , but how do i output the CLOB to a text file, without losing any parts (due to length or indentation) ?
Or maybe do you have other solutions to backup packages or other functions individually (only the one i want, not all of them) ?
Thanks
Trying to get CLOBS (and LONGS) from command line utilities like SQL*Plus always seems to give me formatting/truncation problems. My solution was to write a simple utility in a non- type checking language (Perl) that uses DBMS_METADATA to bring the CLOB back into a string.
Snippet:
...
$sthRef = $dbhRef->prepare("select dbms_metadata.get_ddl(?,?) from dual");
$sthRef->execute('PACKAGE', $thisName);
while (($thisDDL) = $sthRef->fetchrow()) {
print $thisDDL;
}
$sthRef->finish;
...
If you want to get the DDL, there really is no way except DBMS_METADATA like you already said.
Usually, this kind of a backup is done with exp (or expdp), although this doesn't create a SQL file like you would get with most other DBMS systems.
SET pages 0
spool proclist.sql
SELECT
CASE line
WHEN 1 THEN
'CREATE OR REPLACE ' || TYPE || ' ' || NAME || CHR(10) || text
ELSE
text
END
FROM user_source
WHERE TYPE IN ( 'PROCEDURE','FUNCTION')
ORDER BY name, line;
spool OFF
exit
Thanks goes for RAS , guest for his answer ,
I needed to get codes for some procedures only, so I tried the code , to find that this code truncate the code after procedure name in first line of the code and replace it with three dots '...'
so I changed the code to the following:
SELECT CASE line
WHEN 1 THEN 'CREATE OR REPLACE ' -- || TYPE || ' ' || NAME || --CHR(10) || ' ('
|| text
ELSE
text
END
FROM user_source
WHERE TYPE IN ( 'PROCEDURE') and name like 'SomeThing%'
ORDER BY name, line;
and this page
export procedures & triggers
have a very usefaul code:
connect fred/flintstone;
spool procedures_punch.lst
select
dbms_metadata.GET_DDL('PROCEDURE',u.object_name)
from
user_objects u
where
object_type = 'PROCEDURE';
spool off;
Final way to do it by using Toad Schema Browser , then select all the needed procedures and mouse right click then select export from the menu.