Getting the last character in an Oracle CLOB column - oracle

I am having an issue with getting the last character from an Oracle CLOB column. The same SQL that works on an VARCHAR column doesn't work on a CLOB column and can't figure out why or how to make it work.
(this works in getting the last character from a VARCHAR)
select substr(COLUMN_NAME, length(COLUMN_NAME), 1) from TABLE_NAME
(when applied to a CLOB column, it doesn't return the last character.
select substr(CLOB_COLUMN, length(CLOB_COLUMN), 1) from TABLE_NAME
(Updates below)
Per Alex suggestion, I added the dump/cast and get "Typ=1 Len=1: 10" for that column. (I have no idea what that is)
Here is the SQL I was running:
set linesize 32000
select
length(COLUMN_NAME) as clob_length,
substr(trim(COLUMN_NAME), length(trim(COLUMN_NAME)) -50 ) as last_50,
SUBSTR(COLUMN_NAME, -1) as last_char,
dump(cast(substr(COLUMN_NAME, -1) as varchar2(1)))
from TABLENAME
I added the SQL I used and the results for one of my rows are:
CLOB_LENGTH: 1227
LAST_50: shall be permitted to be continued in service
LAST_CHAR:
VARCHAR2(1): Typ=1 Len=1: 10
(I am not clear as to what the last value means)

Works for my simple test case:
SQL> create table test (col clob);
Table created.
SQL> insert into test (col) values ('This is a cloB');
1 row created.
SQL> select substr(col, length(col), 1) from test;
SUBSTR(COL,LENGTH(COL),1)
--------------------------------------------------------------------------------
B
Though, it is simpler to use substr(col, -1) (take the last character):
SQL> select substr(col, -1) from test;
SUBSTR(COL,-1)
--------------------------------------------------------------------------------
B
SQL>

I added the dump/cast and get "Typ=1 Len=1: 10" for that column
As suspected from your image, your CLOB values end with new lines (character 10, which is what the dump output shows), and probably other whitespace, or perhaps line feed (character 13) if the original data came from, say, Word. That's why the 'last 50' isn't showing 50 'normal' characters - there are multiple blank lines taking up some of those positions.
If you want to ignore all of those trailing characters you can change your trim to include more characters, and apply that to both substr calls; something like:
substr(rtrim(clob_column, chr(32)||chr(9)||chr(10)||chr(13)), -1)
which will remove any combination of spaces, tabs, new lines and line feeds.
db<>fiddle showing the 50 character version now appears as a single line, and the last character is null, '.', 'n', 'e' etc.

Related

ORACLE Cannot see apostrophes in my data, when read from SQL DEVELOPER

I'm trying to export a large amount of data from a Oracle DB.
One of the field contains a long string. This field is a VARCHAR2 (2000 chars).
For some reason a string like Mark's dog is shown (and exported) as Mark s dog
Pay attention! Space before the s char, is not a space... is an invisibile char that some editor see as PU2, but I cannot replace it.
Is there a reason for this issue? The production site (not one of mine...) shows the single quote correctly... so it's there somehow.
Thanks
Let's take a look, here's a scenario - I hope it's close to yours.
set sqlformat ansiconsole
drop table missing_quotes purge;
clear screen
create table missing_quotes
(id integer,
words varchar2(2000));
insert into missing_quotes values
(1, 'Mark''s dog');
insert into missing_quotes values
(2, 'Shelly''s cat');
select * from missing_quotes;
And the output -
Table MISSING_QUOTES created.
1 row inserted.
1 row inserted.
ID WORDS
1 Mark's dog
2 Shelly's cat
Now let's do the export. You're not saying how, but we'll just export the query results...as INSERT statements.
And our output -
REM INSERTING into MISSING_QUOTES
SET DEFINE OFF;
Insert into MISSING_QUOTES (ID,WORDS) values (1,'Mark''s dog');
Insert into MISSING_QUOTES (ID,WORDS) values (2,'Shelly''s cat');
Or CSV -
"ID","WORDS"
1,"Mark's dog"
2,"Shelly's cat"
Everything appears to be OK, including the apostrophe in your VARCHAR2(2000).

Oracle vs HANA char data type handling

We have Oracle as source and HANA 1.0 sps12 as target. We are mirroring Oracle to HANA with Informatica CDC through real-time replication. In Oracle, for many columns we have datatype as CHAR i.e. fixed length datatype. As HANA officially doesn't support CHAR datatype so we are using NVARCHAR data type instead of same. Problem we are facing is -as in Oracle CHAR datatype is of fixed length and append spaces whenever actual string is of lesser length than datatype, we have lot of extra spaces in target HANA db for such columns.
For eg. If column col1 has data type
CHAR(5)
and value as 'A', it is replicated in HANA as 'A ' i.e. 'A' appended by four extra spaces, causing lot of problems in queries and data interpretation
Is it possible to implement CHAR like datatype in HANA?
You can use RPAD function in Informatica while transferring data to Hana. Just make sure if Hana doesn't trim automatically.
So, for the CHAR(5) source column you should use:
out_Column = RPAD(input_Column, 5)
Pretty much exactly, as the documentation says:
I don't know HANA and this is more a comment than an answer, but I chose to put it here as there's some code I'd like you to see.
Here's a table whose column is of a CHAR datatype:
SQL> create table test (col char(10));
Table created.
SQL> insert into test values ('abc');
1 row created.
Column's length is 10 (which you already know):
SQL> select length(col) from test;
LENGTH(COL)
-----------
10
But, if you TRIM it, you get a better result, the one you're looking for:
SQL> select length( TRIM (col)) from test;
LENGTH(TRIM(COL))
-----------------
3
SQL>
So: if you can persuade the mirroring process to apply TRIM function to those columns, you might get what you want.
[EDIT, after seeing Lars' comment and re-reading the question]
Right; the problem seems to be just the opposite of what I initially understood. If that's the point, maybe RPAD would help. Here's an example:
SQL> create table test (col varchar2(10));
Table created.
SQL> insert into test values ('abc');
1 row created.
SQL> select length(col) from test;
LENGTH(COL)
-----------
3
SQL> insert into test values (rpad('def', 10, ' '));
1 row created.
SQL> select col, length(col) len from test;
COL LEN
---------- ----------
abc 3
def 10
SQL>

Oracle query looking for particular string format

Am working with an Oracle 11g db in which I need to run a query that returns all rows with values in a specific format.
I.e., I need to find all rows with a value like 'abc1234'. The actual values aren't important....what I need is to find all rows with the first 3 characters being alpha and the subsequent 4 characters all being numeric.
Any input would be much appreciated.
Might not be exact since I don't have an Oracle server handy to test but something like this should get you started in the right direction:
SELECT * FROM your_table WHERE REGEXP_LIKE(your_column, '([a-z]\3[0123456789]\4', 'i')
This will check all rows in your table where the specified column has any alphabet character A to Z three times followed by 4 numbers and return that list. The 'i' at the end just says ignore case on the alphabet part. You can choose to not have that option if you so wish.
Here are a couple links as well with more information on the regexp_like syntax:
Oracle SQL - REGEXP_LIKE contains characters other than a-z or A-Z
https://docs.oracle.com/cd/B28359_01/server.111/b28286/conditions007.htm#SQLRF00501
Try it this will work definitely:
Let's take a sample example:
For example, create a sample table
CREATE TABLE bob (
empno VARCHAR2(10) NOT NULL,
ename VARCHAR2(15) NOT NULL,
ssn VARCHAR2(10) NOT NULL);
Insert data into that table
Insert into bob ( empno,ename,ssn) values ('abC0123458','zXe5378023','0pl4783202');
Insert into bob ( empno,ename,ssn) values ('0123abcdef','a12dldfddd','Rns0101010');
Query to select the all the columns
select * from bob
where length(trim(translate(substr(empno,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(empno,4,4),'0123456789',' '))) IS NULL;
To do the same thing on multiple columns use union operator
select * from bob
where length(trim(translate(substr(empno,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(empno,4,4),'0123456789',' '))) IS NULL;
union
select * from bob
where length(trim(translate(substr(ename,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(ename,4,4),'0123456789',' '))) IS NULL;

How to subtract two columns of Longvarchar in oracle

I have TABLE1 with columns COL1,COL2 defined as LongVarChar in Oracle.
Every time user loads a record to TABLE1, COL1 will have the old value and COL2 will have the old value + new value. i.e.
For ex:
COL1 COL2
Bat
Bat Bat Ball
Bat Ball Bat Ball Wicket
Bat Ball Wicket Bat Ball Wicket Stump
To get the only new value, i am planning to delete contents of COL2 from COL1 contents..I think this is a pretty bad idea..
I tried the usual "-" operator and it says "Expected Numeric but received CLOB"
But does any one any better idea or how to accomplish this?
Thanks so much
Assuming you mean Varchar2, and (as in your example), each old value is separated by an additional space, then something like this should work:
SELECT SUBSTR(col2, NVL(LENGTH(col1)+2,0)) "New Value" FROM TABLE1
eg:
select substr('Bat', nvl(length(null)+2,0)) from dual;
results in 'Bat'
select substr('Bat Ball', nvl(length('Bat')+2,0)) from dual;
results in 'Ball'
But if you're actually talking about a CLOB datatype, then substitute:
dbms_lob.substr( colX, 4000, 1)
instead of colX (where X is 1 or 2)
[This will give you the first 4000 bytes of the CLOB - in order to get more, you'd have to use PL/SQL]

How to show star at first two character of a string in oracle query?

Example if an ID is 1213 i want show **13.
If it's a number
select '**' || substr(to_char(id),3)
from my_table
Or, if it's already a character
select '**' || substr(id,3)
from my_table
This concatenates ** onto the beginning of the string, using the Oracle concatenation operator || and removes the first two characters of the id using substr.
Here's a SQL Fiddle to demonstrate.
If you don't want to sacrifice performance too much, to mask first two characters you can use-
SQL> select regexp_replace('1213','(.)2','**') from dual; --if VARCHAR
MASKED
------------
**13
SQL> select regexp_replace(1213,'(.)2','**') from dual; --if NUMBER
MASKED
------------
**13
REGEXP_REPLACE will work alike on NUMBER and VARCHAR so you save some conversion time there.
Consecutively, you can create a Function Based Index on the regexp function operation to optimize the query like (considering you would always want to mask only first two characters of ID) -
CREATE INDEX
mask_id
ON
table_name
(regexp_replace(id,'(.)2','**'));

Resources