How to compare single byte and multi bytes string? - oracle

I have two strings, one is input from client and other is data in table. Two strings seem to be the same, but has different hex value when I try CAST_TO_RAW.
SELECT UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0A41544258484E') INPUT,
UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E') DTA
FROM DUAL;
/*input and data seem same*/
Consider that two string is the same. How I pass this case and compare them in query like this:
SELECT A.DATA,
A.ORTHER_COL
FROM MYTABLE A
WHERE A.DATA = INPUT;
I tried TO_SINGLE_BYTE but it not work (because of its different LENGTHB):
SELECT *
FROM DUAL
WHERE TO_SINGLE_BYTE(UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0A41544258484E')) =
TO_SINGLE_BYTE(UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E'));
/*return null*/

The two string are not the same; the second one has an extra 000D in the middle:
'3539352F47502D0A41544258484E'
^^^^
'003500390035002F00470050002D000D000A00410054004200580048004E'
^^ ^^ ^^
If they were actually the same you could compare them with implicit conversion (adding the 0D to the first string, but you may prefer to remove it from the second):
SELECT *
FROM DUAL
WHERE UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0D0A41544258484E') =
UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E');
D
-
X
Or explicitly cat to nvarchar2:
SELECT *
FROM DUAL
WHERE cast(UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0D0A41544258484E') as nvarchar2(2000)) =
UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E');
D
-
X
or the other way:
SELECT *
FROM DUAL
WHERE UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0D0A41544258484E') =
cast(UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E') as varchar2(4000));
D
-
X
It's possible you could see some oddities from the casting I suppose, depending on the raw data and the two DB character sets.
From Oracle 12c you could potentially use a UCA linguistic collation that ignores the difference between LF and CRLF, e.g.:
alter session set nls_sort = 'UCA0700_ORADUCET_S1';
alter session set nls_comp = 'LINGUISTIC';
SELECT *
FROM DUAL
WHERE UTL_RAW.CAST_TO_VARCHAR2('3539352F47502D0A41544258484E') =
UTL_RAW.CAST_TO_NVARCHAR2('003500390035002F00470050002D000D000A00410054004200580048004E');
D
-
X
You'd need to see what effect it had on performance though, and whether the other ignorable characters would cause false matches. If you only want to ignore discrepancies between LF/CRLF then you're probably stuck with sanitising the data to be consistent.

Related

In query missing expressions of Oracle SQL Developer

SELECT b.*
FROM buses b,
bus_stations bs,
starts st,
stops_at sa
WHERE st.station_no = ( SELECT station_id
FROM bus_stations
WHERE station_name = "golden mile_Regina"
)
AND sa.station_no = ( SELECT station_id
FROM bus_stations
WHERE station_name = 'westmount_edmonton'
)
ORDER BY DATE;
You can't use double quotes with strings - use single ones, i.e.
WHERE station_name = 'golden mile_Regina'
By the way, are you sure of spelling & letter size? Is it really mixed case, with underscores? Just asking.
Furthermore, you're ordering by DATE - that won't work either, you can't use DATE as a column name (unless you enclose it into double quotes, but I certainly wouldn't recommend that). Have a look at the following example (stupid, yes - setting date to be a number, but I used it just to emphasize that DATE can't be used as a column name):
SQL> create table test (date number);
create table test (date number)
*
ERROR at line 1:
ORA-00904: : invalid identifier
Once you fix that, you'll get unexpected result as there are 4 tables in the FROM clause, but they aren't joined with one another, so that will be a nice Cartesian product.

Oracle 01481. 00000 - "invalid number format model"

This is my query i have used to get the value as money. Nut when concat value getting above exception. The query is
select to_char(b.balance,'9999.'||d.number_of_decimal_places) from balance b, decimal d
Am stuck with this problem.
If you have numeric number_of_decimal_places values like 1, 2, 3 etc. then you are constructing a format model like, for example, '9999.2' instead of '9999.99'.
You can convert that integer value to the format model with rpad or lpad:
select to_char(b.balance,'9999.'||rpad('9', d.number_of_decimal_places, '9'))
from balance b, decimal d
Or for trailing zeros:
select to_char(b.balance,'9999.'||rpad('0', d.number_of_decimal_places, '0'))
from balance b, decimal d
If you have string number_of_decimal_places values like '9', '99', '999' etc. then the concatenation you have will work unless you have an invalid value in one of the rows, which would be any character other than a 9 or a 0.
That includes spaces, which you could have in a varchar2 or char field. Either way you could remove those with trim:
select to_char(b.balance,'9999.'||trim(d.number_of_decimal_places))
from balance b, decimal d
But if you have any other characters then you will need to identify and correct the data in those rows; and even with spaces it would be better to fix the data if it's a varchar2 column.
It would be better to use new-style joins; I haven't changed these examples because it isn't clear if you are doing a cartesian product or have just omitted the join conditions.
If number_of_decimals returns a value like 2 then:
SELECT TO_CHAR( b.balance, RPAD( '9999.', 5 + d.number_of_decimals, '9' ) )
FROM balance b
CROSS JOIN
decimal d
For whatever reason, the concatenation of '9999.'||d.number_of_decimal_places is generating an invalid mask. We can only guess at the actual table values, presence of spaces, or whatever else may be causing issues with what it is doing.
So your solution is to run:
select '9999.'||d.number_of_decimal_places from decimal d
See what the actual format mask is that you are generating, and adjust as necessary.

Oracle cursor removes leading zero

I have a cursor which selects date from column with NUMBER type containg floating point numbers. Numbers like 4,3433 are returned properly while numbers smaller then 1 have removed leading zero.
For example number 0,4513 is returned as ,4513.
When I execute select used in the cursor on the database, numbers are formatted properly, with leading zeros.
This is how I loop over the recors returned by the cursor:
FOR c_data IN cursor_name(p_date) LOOP
...
END LOOP;
Any ideas why it works that way?
Thank you in advance.
You're confusing number format and number value.
The two strings 0.123 and .123, when read as a number, are mathematically equals. They represent the same number. In Oracle the true number representation is never displayed directly, we always convert a number to a character to display it, either implicitly or explicitly with a function.
You assume that a number between 0 and 1 should be represented with a leading 0, but this is not true by default, it depends on how you ask this number to be displayed. If you don't want unexpected outcome, you have to be explicit when displaying numbers/dates, for example:
to_char(your_number, '9990.99');
It's the default number formatting that Oracle provides.
If you want to specify something custom, you shall use TO_CHAR function (either in SQL query or PL/SQL code inside the loop).
Here is how it works:
SQL>
SQL> WITH aa AS (
2 select 1.3232 NUM from dual UNION ALL
3 select 1.3232 NUM from dual UNION ALL
4 select 332.323 NUM from dual UNION ALL
5 select 0.3232 NUM from dual
6 )
7 select NUM, to_char(NUM, 'FM999990D9999999') FORMATTED from aa
8 /
NUM FORMATTED
---------- ---------------
1.3232 1.3232
1.3232 1.3232
332.323 332.323
.3232 0.3232
SQL>
In this example, 'FM' - suppresses extra blanks, '0' indicates number digit including leading/trailing zeros, and '9' indicates digit suppressing leading/trailing zeros.
You can find many examples here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570

Sorting results on Oracle as ASCII

I'm doing a query that returns a VARCHAR2 and some other fields. I'm ordering my results by this VARCHAR2 and having some problems related to the linguistic sort, as I discovered on Oracle documentation. For example:
SELECT id, my_varchar2 from my_table ORDER BY MY_VARCHAR2;
Will return:
ID MY_VARCHAR2
------ -----------
3648 A
3649 B
6504 C
7317 D
3647 0
I need it to return the string "0" as the first element on this sequence, as it would be comparing ASCII values. The string can have more than one character so I can't use the ascii function as it ignores any characters except for the first one.
What's the best way to do this?
For that case, you should be able to just order by the BINARY value of your characters;
SELECT id, my_varchar2
FROM my_table
ORDER BY NLSSORT(MY_VARCHAR2, 'NLS_SORT = BINARY')
SQLFiddle here.

Oracle wm_concat query returns result set with odd characters

My Oracle query produces the correct result set, but data is being presented with odd characters as you can see by the blocks in the picture below.
alt text http://lh3.ggpht.com/_VSEi5_hEznA/TDtsnM9HDnI/AAAAAAAAAD8/zoEzbEaKB9s/blocks.jpg
Any reason that you can think of as to why it would do this and what these characters actually are? Below is the query I'm using. Thanks in advance.
SELECT wmsys.wm_concat(userFirstName) AS firstNames
FROM COURSESECTION
JOIN CLASSCOORDINATOR on classcoord_sectionId = coursesect_sectionId
JOIN usr_USER on classcoord_coordinatorId = userId
GROUP BY classcoord_sectionId;
If I use the same query but use a dump(wmsys.wm_concat(columnName)) then I get the data presented in the picture below.
alt text http://lh3.ggpht.com/_VSEi5_hEznA/TDx2dle4BmI/AAAAAAAAAEM/cP6opWer-Go/concat.jpg
DUMP is my starting point when investigating character set issues.
select wmsys.wm_concat('êõôó'), dump(wmsys.wm_concat('êõôó'))
from dual connect by level < 3;
In my database (AL32UTF8 as shown by querying the NLS_CHARACTERSET parameter from v$nls_parameters), this returns as expected.
How does selecting a simple userFirstName show up ?
I'd suspect that the values have come from a multi-character set environment but have somehow been treated as single character set data.
Edited to add:
I'm able to reproduce this using the following:
select * from v$nls_parameters
where parameter = 'NLS_NCHAR_CHARACTERSET';
AL16UTF16
create table t (v nvarchar2(3));
insert into t values ('a');
select dump(v) from t;
select wmsys.wm_concat(v), v, dump(v), dump(wmsys.wm_concat(v)) from t
group by v;
To remedy, you could try casting the string to a standard VARCHAR2
select wmsys.wm_concat(cast(v as varchar2(3)))
from t
group by v;

Resources