ASCII for SYS_CONNECT_BY_PATH ORACLE sql - oracle

Is there any way to use ascii code for value separator in SYS_CONNECT_BY_PATH.
For example in SYS_CONNECT_BY_PATH(columnname,'!'),
I want to use the ASCII value of !(33) instead of actual symbol. Also, can i use the ascii value of ENTER (13) as value separator?
Thank you.

You can use the chr function to replace a character with it's numeric equivalent.
SYS_CONNECT_BY_PATH(column name, chr(33))
Or to use a line feed, which should also be fine:
SYS_CONNECT_BY_PATH(column name, chr(13))
It's not strictly ASCII as it depends on your character set, but it will probably work for you. You can see the numeric values using the reverse ascii function, which also isn't really quite ASCII, but again close enough especially if you're always using the same character set. So ascii('!') would give you 33.
As you've discovered, giving anything except a fixed string literal gives:
SQL Error: ORA-30003: illegal parameter in SYS_CONNECT_BY_PATH
function
30003. 00000 - "illegal parameter in SYS_CONNECT_BY_PATH function"
*Cause:
*Action: use a non-empty constant string as the second argument,
then retry the operation.
This is why I usually test things before posting, but this seemed so simple... You can get around that with replace:
REPLACE(SYS_CONNECT_BY_PATH(column name, '/'), '/', chr(33))
Borrowing an example from the manual:
SELECT LPAD(' ', 2*level-1)
||replace(SYS_CONNECT_BY_PATH(last_name, '/'),'/',chr(33)) "Path"
FROM employees
START WITH last_name = 'Kochhar'
CONNECT BY PRIOR employee_id = manager_id;
Path
--------------------------------------------------
!Kochhar
!Kochhar!Greenberg
!Kochhar!Greenberg!Faviet
!Kochhar!Greenberg!Chen
!Kochhar!Greenberg!Sciarra
!Kochhar!Greenberg!Urman
!Kochhar!Greenberg!Popp
!Kochhar!Whalen
!Kochhar!Mavris
!Kochhar!Baer
!Kochhar!Higgins
!Kochhar!Higgins!Gietz

All the credit goes to Sanjeev Chauhan. Update 7/25/2017: This turned out to be a SQL Developer 4.2.0 and 17.2.0 bug. In SQLPlus and SQL Developer 3.2.2 the statement works fine.
Fix: set secureliterals off;
The source is https://community.oracle.com/thread/4065282
I had changed the version from 4.2.0 to 4.1.1.19 and my piece of code worked. Also be aware that I couldn't find "secureliterals" in version 4.2.0

Related

Trying to use replace ((value),"\W","") on oracle xquery

Could someone explain why does replace \w (word-character) work and \W (non-word-character) does not .
How to solve it.
create table test (xmldata) as
select xmltype('<workbook>
<worksheet sheetName="asd-kasd" sheetId="1"/>
</workbook>')
from dual;
update test
set XMLDATA=
xmlquery(
'copy $d := .
modify (
for $i in $d/workbook/worksheet/#sheetName
return replace value of node $i with concat("1.\w:",replace(string($i/../#sheetName),"\w",""),"2. \W:",replace($i/../#sheetName,"\W",""))
)
return $d'
passing test.XMLDATA
returning content
);
ORA-19112: error raised during evaluation:
XVM-01126: [FORX0003] Regular expression matches zero-length string
fiddle:
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=ede05cbbe55f36074c36457e9491fc11
Error:
ORA-19112: error raised during evaluation:
XVM-01126: [FORX0003] Regular expression matches zero-length string
after using \W
This seems to be a bug in Oracle's implementation of the standard XQuery fn:replace() function. Using the metacharacter \W causes fn:replace to fail, on every string that I tested. I'd suggest opening a Service Request with Oracle Support to report it.
You can verify using an non-Oracle XQuery tester (e.g. here) that replace() should handle \W just fine.
Oddly, the deprecated ora:replace() function does work correctly. So you could use that as a workaround until Oracle patches the bug. But note that this function is non-standard - for example, it supports POSIX-style metacharacters (e.g. [[:alnum:]]) which the XQuery standard does not.
I simplified your query to give a more minimal verifiable example, and could reproduce the issue on Oracle 12.2.0.1. Comment out the "fn" column to get correct results.
select
regexp_replace('asd-kasd','\W','') as rr, -- normal regexp engine works fine
-- \W fails, with any string
xmlquery('fn:replace("asd-kasd","\W","")' returning content) as fn,
-- deprecated ora:replace works fine
xmlquery('ora:replace("asd-kasd","\W","")' returning content) as ora
from dual
Fiddle

Adaptive Server Enterprise ASCII function for multi-byte characters

While converting from Oracle to Sybase ASE I encounter the following issue: ASCII function doesn't return code for multi-byte characters properly, it looks like it gets only the first byte.
For example, the following statement returns 34655
select ASCII('㍉') from dual
while in Sybase it returns 63
select ASCII('㍉')
Adaptive Server has the following language settings
Language: Japanese
Character Set: eucjis
Even if I use Sybase uscalar function
select uscalar('㍉')
it returns 63
Only passing to uscalar function hex equivalent of this Japanese symbol gives different result, but not the same as in Oracle
select uscalar(0x875F)
returns 24455
But in this way another issue appears - I'm not able to cast this symbol to hex as
select convert(varbinary,'㍉')
returns only the first byte again (0x3f)
Please help me to find out the appropriate way of getting the correct ASCII code of multi-byte Japanese symbols in Adaptive Server Enterprise.

SQLAlchemy: Force column alias quoting

I want SQLAlchemy to generate the following SQL code:
SELECT t171 AS "3Harm" FROM production
I've been playing around with something similar to this SQLAlchemy ORM snippet:
session.query(Production.t171.label('3harm'))
The problem here is that this doesn't properly quote "3harm" in the generated SQL. Instead of "3harm" this generates the unquoted 3harm, which is invalid because it starts with a numerical character and therefore raises the following Oracle exception:
ORA-00923: FROM keyword not found where expected
I can get this to work by capitalizing any character in the alias name:
session.query(Production.t171.label('3Harm'))
But I would still prefer to use all lowercase column names since the rest of my program is standardized for all lowercase. Any idea how to force quote the lowercase version?
Found the solution while looking for something else.
Any column can be forced to use quotes with column.quote = True.
So for the original example:
column = Production.t171.label('3harm')
column.quote = True
session.query(column)
Success!
The SQL you want to generate isn't valid; rather than this:
SELECT t171 AS '3Harm' FROM production
... you need the identifier to be enclosed in double quotes, not single quotes:
SELECT t171 AS "3Harm" FROM production
So it looks like you should be able to do this:
session.query(Production.t171.label('"3harm"'))
or maybe:
session.query(Production.t171.label("3harm"))
But I don't use SQLAlchemy and I don't have any way to check if either is valid; you might need to escape the double quotes in the first one, for instance, though from this perhaps the second is more likely to work... and I don't understand why 3Harm would work unquoted.

Oracle pl-sql escape character (for a " ' ")

When I am trying to execute INSERT statement in oracle, I got SQL Error: ORA-00917: missing comma error because there is a value as Alex's Tea Factory in my INSERT statement.
How could I escape ' ?
To escape it, double the quotes:
INSERT INTO TABLE_A VALUES ( 'Alex''s Tea Factory' );
In SQL, you escape a quote by another quote:
SELECT 'Alex''s Tea Factory' FROM DUAL
Instead of worrying about every single apostrophe in your statement.
You can easily use the q' Notation.
Example
SELECT q'(Alex's Tea Factory)' FROM DUAL;
Key Components in this notation are
q' which denotes the starting of the notation
( an optional symbol denoting the starting of the statement to be fully escaped.
Alex's Tea Factory (Which is the statement itself)
)' A closing parenthesis with a apostrophe denoting the end of the notation.
And such that, you can stuff how many apostrophes in the notation without worrying about each single one of them, they're all going to be handled safely.
IMPORTANT NOTE
Since you used ( you must close it with )', and remember it's optional to use any other symbol, for instance, the following code will run exactly as the previous one
SELECT q'[Alex's Tea Factory]' FROM DUAL;
you can use ESCAPE like given example below
The '_' wild card character is used to match exactly one character, while '%' is used to match zero or more occurrences of any characters. These characters can be escaped in SQL.
SELECT name FROM emp WHERE id LIKE '%/_%' ESCAPE '/';
The same works inside PL/SQL:
if( id like '%/_%' ESCAPE '/' )
This applies only to like patterns, for example in an insert there is no need to escape _ or %, they are used as plain characters anyhow. In arbitrary strings only ' needs to be escaped by ''.
SELECT q'[Alex's Tea Factory]' FROM DUAL
Your question implies that you're building the INSERT statement up by concatenating strings together. I suggest that this is a poor choice as it leaves you open to SQL injection attacks if the strings are derived from user input. A better choice is to use parameter markers and to bind the values to the markers. If you search for Oracle parameter markers you'll probably find some information for your specific implementation technology (e.g. C# and ADO, Java and JDBC, Ruby and RubyDBI, etc).
Share and enjoy.
Here is a way to easily escape & char in oracle DB
set escape '\\'
and within query write like
'ERRORS &\\\ PERFORMANCE';

Count characters after given symbol in oracle varchar column value

How would I go about counting the characters after a certain character. I'm new to Oracle, and I've learned quite a bit however I'm stumped at this point. I found a couple functions that will get you a substring and I found a function that will give you the length of a string. I am examining an email address, myemail#thedomain.com. I want to check the length after the '.' in the email.
SELECT email
FROM user_table
WHERE length(substr(email, /*what values*/, /*to put here*/))
I don't know if it's actually possible to find the location of the final '.' in the email string?
I'm not sure I would use substr. You can try something like this :
select length('abcd#efgh.123.4567') - instr('abcd#efgh.123.4567', '.', -1) from dual
Using instr(..,..,-1) searches backwards from the last character to find the position.
Since you're doing checks, I suggest you validate the format with regular expressions using REGEXP_INSTR. For instance, an email validation I found on this site is REGEXP_INSTR(email, '\w+#\w+(\.\w+)+') > 0
I didn't check it myself, but it looks quite ok.
Cheers.

Resources