How to do simple Substring in Oracle - oracle

How do I do this in Oracle Query? this is saying that we want the records which has '1' inleft most position in that column.
AND substring(convert(varchar,TR.MENU_ID_VALUE), 1, 1) = '1'

The convert function function transforms a string from one character set into another. The syntax is convert(<string>, <to character set>, <from character set>)
Also, substring isn't an Oracle function, it's substr.
If you don't need to convert the string then and substr(tr.menu_id_value,1,1) will get you the leftmost character.
If you do want to convert the character set then the full list is available in the documentation, alternatively you can query v$nls_valid_values. For instance if you're converting from WE8MSWIN1252 (Windows code-page 1252) to AL32UTF8 (UTF-8) then your condition would become:
and substr(convert(tr.menu_id_value,'AL32UTF8','WE8MSWIN1252'),1,1) = '1'
From your comment I'm guessing that convert() is the SQL-Server function to convert between data-types. The Oracle equivalent, in this case, would be to_char. Though Oracle will implicitly do the conversion it is always best to use to_char and convert explicitly; giving you:
and substr(to_char(tr.menu_id_value),1,1) = '1'
Incidentally the exact Oracle equivalent is cast(). Strictly speaking, to_char() should be used if you want to use a format model, thus substr(cast tr.menu_id_value as varchar2(10)),1,1) would also give you what you're after assuming the length of tr.menu_id_value was less than or equal to 10.

Use SUBSTR
AND substr(tr.menu_id_value,1,1) = '1'

Related

Blank character ignored in where clause

I have done the following -
create table test (col char(10));
insert into test values ('hello');
select * from test where col = 'hello'
I have been suggested that the above should not return any result as 'col' is 10 chars, it will be right padded with blanks, so comparing with 'hello' will not return result. But I am getting the result. Can anyone please explain this? I am using 11gR2
Looking at the Oracle Documentation on literals:
Text literals have properties of both the CHAR and VARCHAR2 datatypes:
Within expressions and conditions, Oracle treats text literals as though they have the datatype CHAR by comparing them using blank-padded comparison semantics.
and the documentation of blank-padded comparison semantics states:
With blank-padded semantics, if the two values have different lengths, then Oracle first adds blanks to the end of the shorter one so their lengths are equal. Oracle then compares the values character by character up to the first character that differs. The value with the greater character in the first differing position is considered greater. If two values have no differing characters, then they are considered equal. This rule means that two values are equal if they differ only in the number of trailing blanks. Oracle uses blank-padded comparison semantics only when both values in the comparison are either expressions of datatype CHAR, NCHAR, text literals, or values returned by the USER function.
Since the left-hand side of the comparison is a CHAR(10) and the right-hand side is a text literal then blank-padded comparison semantics are used and 'hello ' = 'hello' is true.
You can see this in the simple example:
SELECT * FROM DUAL WHERE 'hello ' = 'hello';
Update:
[TL;DR] This behaviour has appeared in all versions of Oracle since at least Oracle 7 (released in 1992). I stopped searching for the documentation on releases over two decades old but I expect that you will find that this has been the behaviour in most (all?) versions.
Here is the documentation for the various versions:
Oracle 12c Text Literals & blank-padded semantics
Oracle 11g Text Literals & blank-padded semantics
Oracle 10gR2 Text Literals & blank-padded semantics
Oracle 9 Text Literals & blank-padded semantics
Oracle 8 Text Literals & blank-padded semantics
Oracle 7 Text Literals
You got the correct answer already. Now, you may wonder "how can I force a comparison where the comparison string 'hello' is interpreted as VARCHAR2, so that the query will return no rows?"
The answer is, you must force 'hello' to be seen as VARCHAR2. Like so:
... where col = cast ('hello' as VARCHAR2(10))
(note that the syntax for the cast function requires you to specify the length).
Even though you specify the length of 10, since the cast is as VARCHAR2, the result is really just 5 characters - there is no blank padding of VARCHAR2 values.
Oracle uses "blank padded" comparison semantics in this example because one of the expressions is datatype CHAR and the other expression is a string literal.
There are rules about when Oracle uses blank padded comparison and non-padded comparison semantics. It's covered in the Oracle documentation somewhere.
The suggestion were given (that Oracle would not return a result because the CHAR column would be right padded with spaces) was erroneous.

Update NClob using N Function issues

I am using N function to update NClob in SQL Query. However, the update using N function is not allowing me to update more than 1900 characters. After removing N function. I am able to update the more than 1900 characters to my NClob column.
Can anyone help me as to why I am not able to update the NClob column using N function? Is there any restriction on it?
Code is
StringBuilder updateQuery = new StringBuilder("update table_name set column_name =");
updateQuery.append(" = N'").append(NClobContent).append("'").append(" , ");
ps.execute(updateQuery.toString());
As stated in the documentation:
A text literal can have a maximum length of 4000 bytes.
The N means the literal is using the national character set, which will be either UTF8 or AL16UTF16 (the latter by default), so even if your long string has fewer then 4000 characters, it can still have more then 4000 bytes.
Without the N the string is interpreted in the database character set, and the literal is then converted to the nation character set as it is stored in your NCLOB. You can therefore potentially have a longer string - if your database character set is single-byte then you could ave up to 4000 characters, though any multibyte characters in your NClobCOntent variable would be corrupted.
Rather than using the N syntax, pass your variable to the database as a stream; you might find this answer a useful starting point. Or you might be able to use this approach, depending on the string length.

Different matches when using prepared statements on CHAR(3) column

I had to make a CHAR(1 CHAR) column wider and I forgot to change the column type to VARCHAR2:
DUPLICADO CHAR(3 CHAR)
I noticed the error when my PHP app would no longer find exact matches, e.g.:
SELECT *
FROM NUMEROS
WHERE DUPLICADO = :foo
... with :foo being #4 didn't find the 3-char padded #4 value. However, I initially hit a red herring while debugging the query in SQL Developer because injecting raw values into the query would find matches!
SELECT *
FROM NUMEROS
WHERE DUPLICADO = '#4'
Why do I get matches with the second query? Why do prepared statements make a difference?
To expand a little on my comments, I found a bit in the documentation that explains difference between blankpadded and nonpadded comparison:
http://docs.oracle.com/database/121/SQLRF/sql_elements002.htm#BABJBDGB
If both values in your comparison (the two sides of the equal sign) have datatype CHAR or NCHAR or are literal strings, then Oracle chooses blankpadded comparison. That means that if the lengths are different, then it pads the short one with blanks until they are the same length.
With the column DUPLICADO being a CHAR(3), the value '#4' is stored in the column as three characters '#4 ' (note the blank as third character.) When you do DUPLICADO = '#4' the rule states Oracle will use blankpadded comparison and therefore blankpad the literal '#4' until it has the same length as the column. So it actually becomes DUPLICADO = '#4 '.
But when you do DUPLICADO = :foo, it will depend on the datatype of the bind variable. If the datatype is CHAR, it will also perform blankpadded comparison. But if the datatype is VARCHAR2, then Oracle will use non-padded comparison and then it will be up to you to ensure to do blankpadding where necessary.
Depending on client or client language you may be able to specify the datatype of the bind variable and thereby get blankpadded or nonpadded comparison as needed.
SQL Developer may be a special case that might not allow you to specify datatype - it just possibly might default to bind variables always being datatype VARCHAR2. I don't know sufficient about SQL Developer to be certain about that ;-)

Oracle to_number function parameters

I'm having trouble with TO_NUMBER function second and third parameters. Does one of them depend on the other one? How does nls_params parameter work? I can't understand how the the result of the query
SELECT TO_NUMBER('17.000,23',
'999G999D99',
'nls_numeric_characters='',.'' ')
REFORMATTED_NUMBER
FROM DUAL;
can be 17000.23. Could somebody please explain the process of the above conversion.
P.S. The above query is taken from an Oracle Database SQL Expert Certificate preparation book.
you are telling the TO_NUMBER function that,
the two characters ,. in nls_numeric_characters represent the decimal and thousand seperator
G (thousands seperator) = .
D (decimal seperator) = ,
so it sees the number as seventeen thousand point twenty three.
see: http://download.oracle.com/docs/cd/B13789_01/olap.101/b10339/x_stddev022.htm#i78653
Now, I'll answer my own question. While using TO_NUMBER function I missed the important point that, whatever I get from TO_NUMBER function is going to be a number. And a number does not include anything else than decimal point and E scientific notation. So 17,788.99 is not actually a number but is rather the string representation of 17788.99.
If we try to subtract 500 from 17,788.99 we'll fail.(Well, Oracle implicitly converts numeric strings to numbers and vice-versa, but principally we can't perform arithmetic operations between strings and numbers). I'm sure that TO_NUMBER function is almost never used to select a column value. It's rather used to be able to make arithmetic operations. Instead, we use TO_CHAR to show a column value or any numeric expression in a neat, easy to read format. The fomat models and nls_params are not only for TO_NUMBER function, but for TO_CHAR as well.

Oracle10 and JDBC: how to make CHAR ignore trailing spaces at comparision?

I have a query that has
... WHERE PRT_STATUS='ONT' ...
The prt_status field is defined as CHAR(5) though. So it's always padded with spaces. The query matches nothing as the result. To make this query work I have to do
... WHERE rtrim(PRT_STATUS)='ONT'
which does work.
That's annoying.
At the same time, a couple of pure-java DBMS clients (Oracle SQLDeveloper and AquaStudio) I have do NOT have a problem with the first query, they return the correct result. TOAD has no problem either.
I presume they simply put the connection into some compatibility mode (e.g. ANSI), so the Oracle knows that CHAR(5) expected to be compared with no respect to trailing characters.
How can I do it with Connection objects I get in my application?
UPDATE I cannot change the database schema.
SOLUTION It was indeed the way Oracle compares fields with passed in parameters.
When bind is done, the string is passed via PreparedStatement.setString(), which sets type to VARCHAR, and thus Oracle uses unpadded comparision -- and fails.
I tried to use setObject(n,str,Types.CHAR). Fails. Decompilation shows that Oracle ignores CHAR and passes it in as a VARCHAR again.
The variant that finally works is
setObject(n,str,OracleTypes.FIXED_CHAR);
It makes the code not portable though.
The UI clients succeed for a different reason -- they use character literals, not binding. When I type PRT_STATUS='ONT', 'ONT' is a literal, and as such compared using padded way.
Note that Oracle compares CHAR values using blank-padded comparison semantics.
From Datatype Comparison Rules,
Oracle uses blank-padded comparison
semantics only when both values in the
comparison are either expressions of
datatype CHAR, NCHAR, text literals,
or values returned by the USER
function.
In your example, is 'ONT' passed as a bind parameter, or is it built into the query textually, as you illustrated? If a bind parameter, then make sure that it is bound as type CHAR. Otherwise, verify the client library version used, as really old versions of Oracle (e.g. v6) will have different comparison semantics for CHAR.
If you cannot change your database table, you can modify your query.
Some alternatives for RTRIM:
.. WHERE PRT_STATUS like 'ONT%' ...
.. WHERE PRT_STATUS = 'ONT ' ... -- 2 white spaces behind T
.. WHERE PRT_STATUS = rpad('ONT',5,' ') ...
I would change CHAR(5) column into varchar2(5) in db.
You can use cast to char operation in your query:
... WHERE PRT_STATUS=cast('ONT' as char(5))
Or in more generic JDBC way:
... WHERE PRT_STATUS=cast(? as char(5))
And then in your JDBC code do use statement.setString(1, "ONT");

Resources