Comparing Nvarchar2 field with Varchar2 field in ORACLE database - oracle

so I have the table A with last_name column in varchar2 type, and a table B with last_name column in nvarchar2 type, I want to compare them to find differences
select *
from a
join b
on a.user_id = b.user_id
where CAST(lower(a.last_name) AS varchar2(100)) <> CAST(lower(a.last_name) AS varchar2(100))
but this brings me every row even when their last_name is the same

Related

Oracle 12 equal and not equal (=, !=, <>) behavior about nvarchar2 working problem [duplicate]

This question already has answers here:
Why does Oracle 9i treat an empty string as NULL?
(10 answers)
Closed 2 years ago.
In oracle an empty varchar2 and null are treated the same because Oracle internally changes empty string to NULL values.
Please consider following example :
--1- create table
CREATE TABLE persons(
person_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
first_name VARCHAR2(50) ,
last_name VARCHAR2(50) ,
PRIMARY KEY(person_id)
);
--2-insert sample data
insert into persons (first_name,last_name) values('n1','l1');
insert into persons (first_name,last_name) values('n2',null);
insert into persons (first_name,last_name) values('n3','');
insert into persons (first_name) values('n4');
the following query has result :
select * from persons where last_name is null;
PERSON_ID FIRST_NAME LAST_NAME
2 n2
3 n3
4 n4
and
select * from persons where last_name is not null;
PERSON_ID FIRST_NAME LAST_NAME
1 n1 l1
My question :
1-Why this queries result are “no rows selected”
select * from persons where last_name =''; -- no rows selected
select * from persons where last_name !=''; -- no rows selected
2-More important question is wonderful behavior for the following query:
select * from persons where last_name !='' or last_name =''; -- no rows selected
1-Why this queries result are “no rows selected”
Because the answer lies in your question itself.
select * from persons where last_name =''; -- here '' is converted to NULL
-- so last_name = NULL
-- it will always fail as NULL can not match with other NULL also
select * from persons where last_name !=''; -- - here '' is converted to NULL
-- so last_name != NULL
-- it will always fail as NULL can not mismatch with other NULL also
2-More important question is wonderful behavior for the following query:
select * from persons where last_name !='' or last_name ='';
-- equal or not equal with NULL will always return false.
-- so the result is no rows for this query also
Please note that in any expression if one side is NULL, it will always return false. (IS NULL or IS NOT NULL need to be used for checking null values)

Copy from VARCHAR field to NUMBER field such that VARCHAR value becomes null after being copied to NUMBER field

I have two tables Table1 and Table2 both with the same columns TestResult and Testcounts. Table1 has testresult as varchar and Table2 has testresult as number.
I have a string .for eg "Oracle" as value for testresult of varchar type for Table1 which needs to be inserted to testresult of number type of Table2 as null.How can i do this? Any suggestions will be highly appreciated :)
EDIT
I have table1 with columns as TestResult varchar2(50) and Testcount number with values as "0.5","0.6","0.8","Oracle" for TestResult and 1,2,3,4 for Testcount.
Now i have another table Table2 as TestResult number and Testcount number with no values, in other words its empty.. I would like to insert all data from table1 to table2 with "Oracle" being inserted as "null"
The following will do what you've asked for:
INSERT INTO TABLE2 (TESTRESULT, TESTCOUNTS)
SELECT CASE
WHEN LENGTH(REGEXP_SUBSTR(TESTRESULT, '[0-9.]*')) = LENGTH(TESTRESULT) THEN TESTRESULT
ELSE NULL
END,
TESTCOUNTS
FROM TABLE1
SQLFiddle here
If you only have a single string value that you can't convert to a number, and you want to set that to null, you can just use a case expression to supply the null:
insert into table2 (testresult, testcounts)
select case when testresult = 'Oracle' then null else to_number(testresult) end,
testcounts
from table1;
Demo:
create table table1 (testresult varchar2(10), testcounts number);
insert into table1
select '0.5', 1 from dual
union all select '0.6', 2 from dual
union all select '0.8', 3 from dual
union all select 'Oracle', 4 from dual;
create table table2 (testresult number, testcounts number);
insert into table2 (testresult, testcounts)
select case when testresult = 'Oracle' then null else to_number(testresult) end,
testcounts
from table1;
select * from table2;
TESTRESULT TESTCOUNTS
---------- ----------
.5 1
.6 2
.8 3
4
db<>fiddle
If you are using Oracle 12c Release 2 (or above) you could also just try to convert the string to a number and use the default ... on conversion error clause to substitute null for that, or any other, non-numeric value:
insert into table2 (testresult, testcounts)
select to_number(testresult default null on conversion error), testcounts
from table1;
select * from table2;
TESTRESULT TESTCOUNTS
---------- ----------
.5 1
.6 2
.8 3
4
In earlier versions you could do the same thing with a user-defined function that wraps the real to_number() call and returns null on error. Or a regex/translate check similar to what #BobJarvis has shown.
Having multiple rows with null would make the data hard to interpret though, so hopefully you only have this one fixed value...

Number data type column is not behaving as number

I have a table in oracle which has column recid which is of number Datar type. The table is partition table and it has partition index on it.
When I query the partition like
select * from table partition (abc)
I am able to see value for rec id =50. But when I query
select * from table partition(abc) where rec id =50,
It doesn’t give any record .
If I do type casting as
select * from table partition(abc) where cast (recid as number ) =50
I am getting records.
Please let me know what might be the issue .?
The issue exist only for one partition and rest of the partition working normal.
If it's not behaving as a number, then it's not stored as a number.
Run a DESCRIBE (DESC) on your table in either SQL Developer, SQLcl, or SQL*Plus. It will show how the REC_ID column is defined.
If it's stored as a VARCHAR2, you wil get an error on your WHERE CLAUSE predicate for REC_ID, if not every REC_ID could be treated as also a number:
ORA-01722: invalid number
Like so:
SQL> DESC employees
Name Null? Type
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
EMAIL NOT NULL VARCHAR2(25)
PHONE_NUMBER VARCHAR2(20)
HIRE_DATE NOT NULL DATE
JOB_ID NOT NULL VARCHAR2(10)
SALARY NUMBER(8,2)
COMMISSION_PCT NUMBER(2,2)
MANAGER_ID NUMBER(6)
DEPARTMENT_ID NUMBER(4)
SQL>
SQL> SELECT * FROM employees WHERE first_name = 50;
Error starting at line : 4 in command -
SELECT * FROM employees WHERE first_name = 50
Error report -
ORA-01722: invalid number
SQL> select * from emps_copy_num where first_name = 50;
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DATE JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
100 50 King SKING 515.123.4567 17-JUN-87 AD_PRES 24000 90
The first query fails - because not every value in that column can be simplicity cast as a number by the database.
The second query works, because I created a copy of the table where all of the first_name strings were values that COULD be cast as a number.
You probably have spaces in there somewhere, eg
SQL> create table t ( should_have_been_numeric varchar2(30));
Table created.
SQL>
SQL> insert into t values ('50 ');
1 row created.
SQL> insert into t values (' 50 ');
1 row created.
SQL> insert into t values (' 50');
1 row created.
SQL>
SQL> select * from t where should_have_been_numeric = '50';
no rows selected
SQL> select * from t where cast(should_have_been_numeric as number) = 50;
SHOULD_HAVE_BEEN_NUMERIC
------------------------------
50
50
50
3 rows selected.
but as already mentioned, if you are treating strings as numbers, then there is problems ahead in terms of spurious errors, not to mention potential performance issues because the optimizer also doesn't know that these are really numbers.

Why does full outer join in HIVE gives weird result when one of the join fields is missing?

I'm comparing the behavior between SQL engines. Oracle has the behavior I would expect from a SQL engine for full outer joins:
Oracle
CREATE TABLE sql_test_a
(
ID VARCHAR2(4000 BYTE),
FIRST_NAME VARCHAR2(200 BYTE),
LAST_NAME VARCHAR2(200 BYTE)
);
CREATE TABLE sql_test_b
(
NUM VARCHAR2(4000 BYTE),
FIRST_NAME VARCHAR2(200 BYTE),
LAST_NAME VARCHAR2(200 BYTE)
);
INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('1', 'John', 'Snow');
INSERT INTO sql_test_a (ID, FIRST_NAME, LAST_NAME) VALUES ('2', 'Mike', 'Tyson');
INSERT INTO sql_test_b (NUM, FIRST_NAME, LAST_NAME) VALUES ('20', 'Mike', 'Tyson');
When I execute the following, it gives me the expected result. The resulting table contains two rows, with one of the rows containing NULL for the NUM field, because there is no john snow in the table sql_test_b.
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;
You can test the sql script here: http://sqltest.net/
HIVE
In HIVE, however, if you were to try the same thing, the full outer join results in a table with two rows. The row that should be the "John Snow" row contains NULL for the fields FIRST_NAME, LAST_NAME, and NUM. The 1 is filled in for ID, but that's it.
Why such weird behavior in HIVE? Is this a bug? Or am I missing something...because Oracle 11g seems to handle this much better. Thanks.
I could not simulate the result reported by #Candic3
I used the below statements along with the same "select" query as in the question.
CREATE TABLE IF NOT EXISTS sql_test_a (ID String, FIRST_NAME String, LAST_NAME String) COMMENT 'sql_test_a'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
CREATE TABLE IF NOT EXISTS sql_test_b (NUM String, FIRST_NAME String, LAST_NAME String) COMMENT 'sql_test_b'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
INSERT INTO sql_test_a VALUES ('1', 'John', 'Snow');
INSERT INTO sql_test_a VALUES ('2', 'Mike', 'Tyson');
INSERT INTO sql_test_b VALUES ('20', 'Mike', 'Tyson');
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;
Please find the result attached.
However, select query would return NULL due to unnoticed minor mistakes like data-type mismatch between the DDL and the actual data (say, from flat files) or mismatch among the delimiter mentioned in the DDL and the ones in the actual data.
I think issue with "(" after on condition which is slightly different than traditional sql.
SELECT A.FIRST_NAME, A.LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B ON
(A.FIRST_NAME = B.FIRST_NAME AND A.LAST_NAME = B.LAST_NAME);
In select statement you have used A.FIRST_NAME, A.LAST_NAME which is not present for the row from table B. That is why the null value. Instead use COALESCE to find non null value between A.FIRST_NAME and B.FIRST_NAME
SELECT COALESCE(A.FIRST_NAME, B.FIRST_NAME) as FIRST_NAME, COALESCE(A.LAST_NAME, B.LAST_NAME) as LAST_NAME, A.ID, B.NUM
FROM
SQL_TEST_A A
FULL OUTER JOIN
SQL_TEST_B B
ON
A.FIRST_NAME = B.FIRST_NAME
AND
A.LAST_NAME = B.LAST_NAME;

Oracle changes encoding

select rawtohex(UNISTR('\0436')) from dual
returns 0436
update my_table set my_column = UNISTR('\0436') where id = 248149;
SELECT rawtohex(my_column) from my_table where id = 248149;
returns E6
so I put symbol in UTF8 and get it back in CP1251. Why so?
You are saving the unicode string into varchar2 column. Consider saving them in the nvarchar2 type columns.
create table my_table
(
id number(10),
my_column varchar2(100),
my_column_uni nvarchar2(100)
);
insert into my_table values(1, UNISTR('\0436'), UNISTR('\0436'));
commit;
select rawtohex(my_column), rawtohex(my_column_uni)
from my_table
where id = 1;
The output will be E6 for varchar2 column and 0436 for nvarchar2 column. Oracle changes the encoding based on your nls parameters, where you have NLS_CHARACTERSET and NLS_NCHAR_CHARACTERSET NLS parameters. You can query your specific parameters by.
select *
from nls_database_parameters

Resources