Oracle wm_concat query returns result set with odd characters - oracle

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;

Related

Oracle query in stored procedure

i'm working with stored procedures, i have a query that should bring one specific id
SELECT * into SID_INCOMING FROM
(
SELECT SID
FROM TBL_INCOMING
WHERE XKEY = ''||nro_tarjetatmp||'_'||fecha_hr_trasacfinal||'_'||datos_referencia_adquirentetmp||''
AND CODIGO_AUTORIZACION IN(''||codigo_autorizacion||'')
AND MIT IN(''||mit||'')
ORDER BY SID ASC
) WHERE ROWNUM <= 1;
the variables values are in order
4946110112060005_200116_74064350165099586691985
536018
05
when it's executed i get this result
but when i execute the same query with the same parameters i get this result
and this is the one i sould get with the procedure, so why is this happening?
it seems to me, that the sp is not considering the second and third parameter
any help is welcome, thanks
You need to use aliases to avoid your problem with AND MIT IN(''||mit||''): this predicate compares column MIT with itself.
SO just add aliases:
SELECT * into SID_INCOMING FROM
(
SELECT SID
FROM TBL_INCOMING ti
WHERE ti.XKEY = ''||your_proc_name.nro_tarjetatmp||'_'||your_proc_name.fecha_hr_trasacfinal||'_'||your_proc_name.datos_referencia_adquirentetmp||''
AND ti.CODIGO_AUTORIZACION IN(''||your_proc_name.codigo_autorizacion||'')
AND ti.MIT IN(''||your_proc_name.mit||'')
ORDER BY ti.SID ASC
) WHERE ROWNUM <= 1;
Also why do you add ''||? It doesn't add anything into your variables, but forces impicit type conversion in cases when they are not varchar2/char data types.
Could you show the results of "describe TBL_INCOMING" please? Since looks like CODIGO_AUTORIZACION is a number data type and probably MIT is number too.

Retrieving data from oracle table using scala jdbc giving wrong results

I am using scala jdbc to check whether a partition exists for an oracle table. It is returning wrong results when an aggregate function like count(*) is used.
I have checked the DB connectivity and other queries are working fine. I have tried to extract the value of count(*) using an alias, But it failed. Also tried using getString. But it failed.
Class.forName(jdbcDriver)
var connection = DriverManager.getConnection(jdbcUrl,dbUser,pswd)
val statement = connection.createStatement()
try{
val sqlQuery = s""" SELECT COUNT(*) FROM USER_TAB_PARTITIONS WHERE
TABLE_NAME = \'$tableName\' AND PARTITION_NAME = \'$partitionName\' """
val resultSet1 = statement.executeQuery(sqlQuery)
while(resultSet1.next())
{
var cnt=resultSet1.getInt(1)
println("Count="+cnt)
if(cnt==0)
// Code to add partition and insert data
else
//code to insert data in existing partition
}
}catch(Exception e) { ... }
The value of cnt always prints as 0 even though the oracle partition already exists. Can you please let me know what is the error in the code? Is this giving wrong results because I am using scala jdbc to get the result of an aggregate function like count(*)? If yes, then what would be the correct code? I need to use scala jdbc to check whether the partition already exists in oracle and then insert data accordingly.
This is just a suggestion or might be the solution in your case.
Whenever you search the metadata tables of the oracle always use UPPER or LOWER on both side of equal sign.
Oracle converts every object name in to the upper case and store it in the metadata unless you have specifically provided the lower case object name in double quotes while creating it.
So take an following example:
-- 1
CREATE TABLE "My_table_name1" ... -- CASE SENSISTIVE
-- 2
CREATE TABLE My_table_name2 ... -- CASE INSENSITIVE
In first query, we used double quotes so it will be stored in the metadata of the oracle as case sensitive name.
In second query, We have not used double quotes so the table name will be converted into the upper case and stored in the metadata of the oracle.
So If you want to create a query against any metadata in the oracle which include both of the above cases then you can use UPPER or LOWER against the column name and value as following:
SELECT * FROM USER_TABLES WHERE UPPER(TABLE_NAME) = UPPER('<YOUR TABLE NAME>');
Hope, this will help you in solving the issue.
Cheers!!

How to compare single byte and multi bytes string?

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.

birt sql dataset with parameters sql error

I have a birt dataset for a db2 query. My query works fine without parameters with the following query...
with params as (SELECT '2014-02-16' enddate,'1' locationid FROM sysibm.sysdummy1)
select
t.registerid
from (
select
...
FROM params, mytable sos
WHERE sos.locationid=params.locationid
AND sos.repositorytype ='xxx'
AND sos.repositoryaccountability='xxx'
AND sos.terminalid='xxx'
AND DATE(sos.balanceDate) between date(params.enddate)-6 DAY and date(params.enddate)
GROUP BY sos.terminalid,sos.balancedate,params.enddate) t
GROUP BY
t.registerid
WITH UR
But when I change the top line to ...
with params as (SELECT ? enddate,? locationid FROM sysibm.sysdummy1)
And make the two input paramters of string datatype I get db2 errors sqlcode -418. But i know that it is not my querty because my query works.
What is the right way for me to set up the parameters so there is no error?
thanks
I'm not familiar with DB2 programming, but on Oracle the ? works anywhere in the query.
Have you looked at http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=%2Fcom.ibm.db2z9.doc.codes%2Fsrc%2Ftpc%2Fn418.htm?
Seems that on DB2 it's a bit more complicated and you should use "typed parameter markers".
The doc says:
Typed parameter marker
A parameter marker that is specified with its target data type. A typed parameter marker has the general form:
CAST(? AS data-type)
This invocation of a CAST specification is a "promise" that the data type of the parameter at run time will be of the data type that is specified or some data type that is assignable to the specified data type.
Apart from that, always assure that your date strings are in the format that the DB expects, and use explicit format masks in the date function, like this:
with params as (
SELECT cast (? as varchar(10)) enddate,
cast (? as varchar2(80)) locationid
FROM sysibm.sysdummy1
)
select
...
from params, ...
where ...
AND DATE(sos.balanceDate) between date(XXX(params.enddate))-6 DAY and date(XXX(params.enddate))
...
Unfortunately I cannot tell you how the XXX function should look on DB2.
On Oracle, an example would be
to_date('2014-02-18', 'YYYY-MM-DD')
On DB2, see Converting a string to a date in DB2
In addition to hvb answer, i see two options:
Option 1 you could use a DB2 stored procedure instead of a plain SQL query. Thus there won't be these limitations you face to, due to JDBC query parameters.
Option 2, we should be able to remove the first line of the query "with params as" and replace it with question marks within the query:
select
t.registerid
from (
select
sos.terminalid,sos.balancedate,max(sos.balanceDate) as maxdate
FROM params, mytable sos
WHERE sos.locationid=?
AND sos.repositorytype ='xxx'
AND sos.repositoryaccountability='xxx'
AND sos.terminalid='xxx'
AND DATE(sos.balanceDate) between date(?)-6 DAY and date(?)
GROUP BY sos.terminalid,sos.balancedate) t
GROUP BY
t.registerid
A minor drawback is, this time we need to declare 3 dataset parameters in BIRT instead of 2. More nasty, i removed params.endDate from "group by" and replaced it with "max(sos.balanceDate)" in select clause. This is very near but not strictly equivalent. If this is not acceptable in your context, a stored procedure might be the best option.

Sensitive query search in oracle

SELECT VALUE FROM BILL WHERE VALUE='ABC123';
search results would bring back records with abc123, ABC123, aBc123, ABc123 also
Can any one please help me?
Two possible solutions:
First:
SELECT value
FROM bill
WHERE upper(VALUE) = 'ABC123';
Second:
ALTER SESSION SET nls_comp = Linguistic;
ALTER SESSION SET nls_sort = XGerman_CI; -- or any other language, e.g. XWEST_EUROPEAN_CI
SELECT value
FROM bill
WHERE VALUE = 'ABC123';
The _CI suffix of the nls_sort parameter tells Oracle to compare "case insensitive".
In both cases Oracle won't use an index unless you create a function based index.
For a complete list of possible NLS_SORT values, see the manual: http://docs.oracle.com/cd/E11882_01/server.112/e10729/applocaledata.htm#i637232
use upper or lower function and give the exact value you need.
select value from bill where upper(value)='ABC123'
If you need all the value like abc,aBc,Abc,etc you can use below in where condition with your requirement
value in ('abc','aBc','Abc','ABC')
You should write:
SELECT VALUE FROM BILL WHERE upper(VALUE)='ABC123';
But you'll loose the benefit of index on value, if exists.
However, you may create a function based index on upper(value).

Resources