SQLDeveloper query automatic padding CHAR field - oracle

Given the table ATABLE with a field AFIELD of type CHAR(8), and where i have a field with value "1234567 "
Why, in SQL Developer, if I query:
SELECT * FROM ATABLE WHERE AFIELD = '1234567';
It will automatically pad the missing space and return the results, and if I query with :
SELECT * FROM ATABLE WHERE AFIELD = :value;
and input the value, it wont ?

From the documentation:
Within expressions and conditions, Oracle treats text literals as though they have the data type CHAR by comparing them using blank-padded comparison semantics.
When you do WHERE AFIELD = '1234567' the text literal '1234567' is treated as char and blank-padded comparison semantics are used to compare the column value and the literal. Even though the literal doesn't have the trailing space, those semantics see them as the same, so it finds a match.
When you use a bind variable the literal you assign to it is a char, but the bind variable itself is varchar2 - even if you declare it as char, oddly, though in that case the value is blank-padded anyway:
var char_value char(8);
exec :char_value := '1234567';
var varchar2_value varchar2(8);
exec :varchar2_value := '1234567';
select dump('1234567') as d1, dump(:char_value) as d2, dump(:varchar2_value) as d3
from dual;
D1 D2 D3
------------------------------------ ------------------------------------ ------------------------------------
Typ=96 Len=7: 49,50,51,52,53,54,55 Typ=1 Len=8: 49,50,51,52,53,54,55,32 Typ=1 Len=7: 49,50,51,52,53,54,55
The text literal is data type 96 (char), while both bind variables are type 1 (varchar/varchar2); but notice the char_value bind variable has the trailing space, with length 8 and the last character as code point 32.
When you compare your char column value with a varchar2 bind variable the column value is implicitly converted from char to varchar2:
The following rules govern implicit data type conversions:
During SELECT FROM operations, Oracle converts the data from the column to the type of the target variable.
So your space-padded char(8) column value is implicitly converted to varchar2(8) to match the bind variable's data type, and then because they are varchar2 the nonpadded comparison semantics are used.
When you compare your char(8) column with the supposedly-char(8) bind variable, you're actually comparing with a padded varchar2(8) - but both the implicitly converted column value and the blank-padded bind variable are actually the same, both with the trailing space; '1234567 ' is the same as '1234567 ', so there is a match, even with nonpadded comparison semantics.
With the varchar2(8) bind variable the same thing happens, but now the bound value is not padded, and as you are using nonpadded comparison semantics to compare '1234567 ' with '1234567' - they are not the same, so there is no match, and no data is returned by the query.
As #a_horse_with_no_name said you should almost always use varchar2 rather than char. But if you must use it and are stuck with it then at least make sure you use the same data type for comparisons.

You are right
SELECT * FROM ATABLE WHERE AFIELD = :value;
does not work with CHAR as you desire.
Anyway I have noticed that the following query works as you desire:
SELECT * FROM ATABLE WHERE AFIELD = &value;
If you use &value in several places, you can use &&value (double &) the first time (and &value elsewhere),
in order to avoid to input the same value several times;
when you have to change that value, you can undefine it with:
undef value;

Related

Why can't I trim a column of type CHAR?

Like the title says, if a create a table in my DB :
CREATE TABLE TEST
(
FIELD CHAR(20 CHAR) NULL
)
NOLOGGING
NOCOMPRESS
NOCACHE;
Insert this :
Insert into TEST
(FIELD)
Values
('TEST -here are blank spaces- ');
COMMIT;
Then i run the following statement :
UPDATE TEST SET FIELD = TRIM(FIELD);
COMMIT;
but the field still has blank spaces, notice that if I change the data type to varchar2, it works ... does anyone know why?
Thanks!
char is a fixed width data type. A char(20) will always and forever have a length of 20. If you try to insert a shorter string, it will be padded with spaces to the fixed width length of the field. So
UPDATE TEST SET FIELD = TRIM(FIELD);
removes the spaces due to the trim function, then adds them back because the string that gets written has to be exactly 20 bytes long.
Practically, there is almost never a case to use char. You're almost always better off with a varchar2. varchar2 is a variable length data type so there is no need for the database to append the spaces to the end.

How to insert a blank value instead of NULL in Columns other than String datatype in hive

I have a create statement like
CREATE TABLE temp_tbl (EmpId String,Salary int);
I would like to insert an employee id and a blank value into table.
So What I have done is
insert overwrite table temp_tbl select '013' as EmpId,'' as Salary from tbl;
hive> select * from temp_tbl;
OK
013 NULL
But expected result is
hive> select * from temp_tbl;
OK
013 NULL ---> Blank instead of NULL
Also tried with "". Still I get it as NULL instead of blank
3.Tried to create table with serialization property
CREATE TABLE temp_tbl (EmpId String,Salary int) TBLPROPERTIES ('serialization.null.format' = '');
That too didn't change NULL value to blank.
What can be the workaround for the same.
Use Case while selecting the data.
Select
(CASE
WHEN columnName is null THEN ''
ELSE columnName
END) as 'Result' from temp_tbl;
All types except strings/varchar/char and some complex types like array, in Hive cannot be blank, only NULL is possible. Empty string '' is quite normal value of type String. You can produce empty array() as well (Array with zero size).
As a workaround, you can use some predefined values which are not normally in your data to represent some special numeric values, like -99999. Alternatively you can store your numeric values in a String column, in such case you will be able to have empty values in it. But it's not possible to assign (cast) empty strings to numeric types, because such empty value is not allowed.
If you try to assign empty string to numeric column or cast to numeric type, the result will be the same as if you are converting non-numeric string to numeric - NULL (in Hive if not possible to cast, it returns NULL) or get java.lang.NumberFormatException in Java.
Knowing that datatype Int can be either NULL or integer , I'd think of how to work around the problem.
I have the impression that 0 can do the job. Why can it not?
If 1 is not ideal, why not create a new temp_employees_with_no_salary table?
If 2 is not ideal, can you afford to change the datatype of temp_tbl.Salary from Int to String, then use CAST(Salary AS INT) to work with it?

I want to export data from oracle database to csv, and I am putting a number filter on a varchar column. It thows ORA:01722 error. Please suggest

Select count(*) from table where loc between 300 to 400.
loc is a varchar column.
it is not selecting all the data
checking the count, gives ORA :01722 error
exporting the results with error.
Edit from comment:
loc contains values less than 300, more than 400, and alphanumeric like 'GT' , '3KT1'
loc is a varchar column.
[From comment] The Loc column has char type value also like GJ, 3KT1
LOC contains values which are not convertible to numbers. This matters because your WHERE clause predicates are defined as numbers, so Oracle applies an implicit to_number(loc) to the query. This is why using proper data types is best practice: it doesn't help you now but please learn the lesson, and use NUMBER columns for numeric data.
In the meantime you have several options to deal with your shonky data model.
If you're lucky enough to be using Oracle 12c R2 you can use the new VALIDATE_CONVERSION() function to exclude values of loc which can't be cast to numbers. Find out more
If you're using an earlier version of Oracle you can build your own function:
create or replace function is_number
(p_str in varchar2) return number
is
n number;
rv number;
begin
begin
n := to_number(p_str);
rv := 1;
exception
when invalid_number then
rv := 0;
end;
return rv;
end;
The weakest option would be casting the predicates to strings. where loc between '300' to '400' would include '3000', '4' and various other values you probably don't want.
Here is a LiveSQL demo (free Oracle Technet account required, alas).
Your current query is trying to compare a varchar to a number. So it tries to convert the varchar to a number on the fly. This is called implicit conversion.
You should make it compare a varchar to a varchar.
Use single quotes so that you are comparing to varchars, not numbers
Select count(*) from table where loc between '300' to '400'
Then go and read about implicit conversion
Based on the update to your question, this column is a legitimate varchar and should not be converted to a numeric data type.
However you do need to work out whether you are incorrectly storing different types of data in the same column

Oracle user defined records

In Oracle PL/SQL records we can use anchor datatypes (including %TYPE and %ROWTYPE) to define the fields.
When I populate a record from a query, in my select clause I want type conversion. Is that possible using an Oracle built-in function or some other approach?
In this example scenario I am using a simple decode function to perform a conversion:
DECLARE
TYPE TEST_RECORD IS RECORD(
FIRST_NAME EMPLOYEE_MT.FIRST_NAME%TYPE,
LAST_NAME EMPLOYEE_MT.LAST_NAME%TYPE,
MARITIAL_STATUS EMPLOYEE_MT.MARITAL_STATUS%TYPE);
EMPLOYEE_NAME TEST_RECORD;
BEGIN
SELECT EMP.FIRST_NAME,
EMP.LAST_NAME,
DECODE(EMP.MARITAL_STATUS, 1, 'MARRIED', 0, 'UN-MARRIED')
INTO EMPLOYEE_NAME
FROM EMPLOYEE_MT EMP
WHERE EMP.EMPLOYEE_ID = 1;
DBMS_OUTPUT.put_line(EMPLOYEE_NAME.MARITIAL_STATUS);
END;
which gets error:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 9
You have defined your record type with the maritial_status (shouldn't that be marital_status?) field using the same data type as the table column. From your decode that appears to be a number data type. You're then trying to set the record's field value to a string, either 'MARRIED' or 'UN-MARRIED', when that field is expecting a number. Clearly neither of those strings can be converted to a number, hence the error you're getting.
If you want the record to store the string value, you'll have to define it like that - explicitly as a string, rather than using %TYPE:
DECLARE
TYPE TEST_RECORD IS RECORD(
FIRST_NAME EMPLOYEE_MT.FIRST_NAME%TYPE,
LAST_NAME EMPLOYEE_MT.LAST_NAME%TYPE,
MARITAL_STATUS VARCHAR2(10));
...
DBMS_OUTPUT.put_line(EMPLOYEE_NAME.MARITAL_STATUS);
...
You can't do that automatically using %TYPE as the data type just doesn't match. You've explicitly told Oracle that you want the field's data type to be a number, so Oracle isn't going to let you put a string in that field instead. It isn't about there not being a built-in function, it just doesn't make sense.
This also means you can't use %ROWTYPE if you're changing the data type either (unless your modified value can be implicitly converted back to the column data type).

Cannot update a row with a bind variable in UPDATE statement

I am using Oracle SQL Developer 4.0.0.13.
Query :
UPDATE employes
SET emptime = systimestamp
WHERE emp_id = 123
AND emp_device = :abc;
Field Definition : emp_device char(20 byte)
Value is : 99998000000008880999 (This value is present in the table)
When I run the above query in SQL developer it asks me to give the value for the bind variable, which I paste in the text box and it returns 0 rows updated.
But when I remove the bind variable in the update query and specify the actual value, it updates the column value. Below is the query.
Query:
UPDATE employes
SET emptime = systimestamp
WHERE emp_id = 123
AND emp_device = 99998000000008880999 ;
---(works)
Also, when I add some trailing spaces in the bind variable text box and trim the emp_device column, it updates the column. Below is the query.
Query :
UPDATE employes
SET emptime = systimestamp
WHERE emp_id = 123
AND emp_device = trim(:abc);
-- (works --- :abc value is '99998000000008880999 ')
I do not know what is wrong with it. Can someone please take a look and suggest a solution.
You are using CHAR type for your emp_device datatype. Note that CHAR type always blank pads the resulting string out to a fixed width.read this.
You should use VARCHAR2 as datatype if you are expecting a string or just NUMBER as your example consists purely of numeric values.
in dialog box enter your parameter as '99998000000008880999' use apostrophe chars.

Resources