Oracle change column type from CLOB to NCLOB - oracle

We are using Oracle and we have a requirement to allow greek characters to be stored in the DB. Currently, our DB instance doesn't let us insert greek characters such as 'ϕ'. On googling, I found that it is to do with the character set. My oracle uses NLS_CHARACTERSET - WE8MSWIN1252 that doesn't support greek characters. I will have to change the character set to one of AL32UTF8, UTF8, AL16UTF16 or WE8ISO8859P7 if it has to work. Now that we have so much of data in the DB already, it would be a risk to change the character set now.
The other option I have is to change the column type (used to insert greek) from CLOB or VARCHAR2 to NVARCHAR2 and it works fine.
Before changing the column type, I want to know what are the risks involved in changing column type from CLOB to NVARCHAR2 and what are the things I need to keep in mind before changing.
Also, I would like to know the pros and cons of changing my existing character set to AL32UTF8.
EDIT:
There is also an option of changing CLOB to NCLOB and this seems to be less risky as both are closely related (almost same) types. Please do let me know the pros and cons of changing CLOB to NCLOB.

Ok. I was googling and posting Qs in other forums and got a much needed answer in here.
https://www.toolbox.com/tech/oracle/question/migrating-clob-to-nclob-010917/

So I just encountered this myself and I had issues with the above solution as it didn't copy across the foreign keys and constraints of my other columns. To get round this I did the following
created a new column for my NCLOB data,
ALTER TABLE table_name
ADD new_table_column NCLOB;
I then copied my CLOB data into my new NCLOB data column using the TO_NCLOB() function
UPDATE table_name
SET new_table_column = TO_NCLOB(old_table_column);
3)Finally I dropped the old column and then renamed my new column to my old column name
ALTER TABLE table_name
DROP COLUMN old_table_column;
ALTER TABLE table_name
RENAME COLUMN new_table_column TO old_table_column;
Please make sure you backup your data if you do this though as dropping the column will get rid of it and commit any transactions you've got
I also did this in Oracle so the syntax may differ slightly in other versions of SQL.

Related

Is it possible to set a BLOB size when creating table?

I am new to Oracle sql, but I have some experience with MSSQL. I was sent a script to create some tables, but because of the BLOB columns, I am getting a couple errors when I try to limit the size.
I tried asking my co-workers about this, but they aren't sure either. This was basically grabbed from somewhere else, so they're not sure how to fix this.
Essentially, the table looks something like this (table and column names were changed):
CREATE TABLE table1
(
ID CHAR(32),
NAME CHAR(50),
KEY $(BLOB)(64),
BUFFER $(BLOB)(20),
SORTNO NUMERIC(8) CONSTRAINT UK_WIU UNIQUE,
CONSTRAINT PK_ID PRIMARY KEY (ID)
)
;
When running this, I get the error "invalid character" because of the dollar sign ($). But if I change data type to BLOB(64), I get an error saying "missing right parenthesis." If I just do "BLOB," it runs fine. Is there any way to define the length for BLOB?
Thank you
BLOB column's size can't be restricted. It allows you to store up to [(4 gigabytes - 1) * (database block size)] data, and that's it. If you need less than that, fine, no problem.
More about BLOB (and other Oracle 18c datatypes) here: https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/Data-Types.html#GUID-1A71C635-188E-4EC9-B821-1DBEC2B45451
Table you meant to create would in Oracle look like this:
SQL> create table table1
2 (id varchar2(32) constraint pk_id primary key,
3 name varchar2(50),
4 sortno number(8) constraint uk_wiu unique,
5 key blob,
6 buffer blob
7 );
Table created.
SQL>
Yet another objection regarding your code: don't use CHAR but VARCHAR2 (unless you have to); CHAR will right-pad values with spaces, up to the maximum length of the column.
No, columns are just defined as a CLOB or BLOB.
There is no size associated with the column. You can put in something as big or small as you like, with a few restrictions.
"Maximum size: (4 GB - 1) * DB_BLOCK_SIZE initialization parameter (8 TB to 128 TB)"..as of 11g of Oracle.
To limit the size, you could, do so at the application layer - prevent folks from uploading files larger than X, although someone with DB access could do this.
You could write a stored procedure for handling INSERT/UPDATES, and have logic in there to prevent DML if the size is 'too large.'
You might be able to do a check constraint using a function call to get the length of the lob...an example here

Oracle PLSQL Alter/Drop Attributes of Object Type

I am new to Oracle PLSQL and have to Alter an Object Type. I´ve made many mistakes with the data types of the new Columns, so I had to drop them and altered them a second time.
For example, I did this:
ALTER TYPE testObjectType ADD ATTRIBUTE (Prename VARCHAR2(50))
ALTER TYPE testObjectType DROP ATTRIBUTE Prename
ALTER TYPE testObjectType ADD ATTRIBUTE (Prename VARCHAR2(50 CHAR))
Now below the "Create or Replace" - Code of the Object there are many lines of code about adding & dropping Attributes. I´ve to try to simply delete this lines but the changes don't work at all. How can I tidy up my Object-Type? (I'm using Oracle SQL Developer).
You need to reset it so it is no longer treated as an evolved type:
alter type testobjecttype reset;
Then you can rebuild it with:
create or replace type testobjecttype as object
( prename varchar2(50 char) );
(plus any other attributes etc it should have).
btw there isn't much point naming database objects in CamelCase as the database ignores it, and schema browsers will just list it in uppercase (because that's how the dictionary stores names), which can become hard to read without word separators. (And shouldn't it be TestObjectType anyway?) There is a better case for it in naming program variables, although they are case-insensitive as well, so it's probably simplest and cleanest to just code in lowercase.

How to store unlimited characters in Oracle 11g?

We have a table in Oracle 11g with a varchar2 column. We use a proprietary programming language where this column is defined as string. Maximum we can store 2000 characters (4000 bytes) in this column. Now the requirement is such that the column needs to store more than 2000 characters (in fact unlimited characters). The DBAs don't like BLOB or LONG datatypes for maintenance reasons.
The solution that I can think of is to remove this column from the original table and have a separate table for this column and then store each character in a row, in order to get unlimited characters. This tble will be joined with the original table for queries.
Is there any better solution to this problem?
UPDATE: The proprietary programming language allows to define variables of type string and blob, there is no option of CLOB. I understand the responses given, but I cannot take on the DBAs. I understand that deviating from BLOB or LONG will be developers' nightmare, but still cannot help it.
UPDATE 2: If maximum I need is 8000 characters, can I just add 3 more columns so that I will have 4 columns with 2000 char each to get 8000 chars. So when the first column is full, values would be spilled over to the next column and so on. Will this design have any bad side effects? Please suggest.
If a blob is what you need convince your dba it's what you need. Those data types are there for a reason and any roll your own implementation will be worse than the built in type.
Also you might want to look at the CLOB type as it will meet your needs quite well.
You could follow the way Oracle stored their stored procedures in the information schema. Define a table called text columns:
CREATE TABLE MY_TEXT (
IDENTIFIER INT,
LINE INT,
TEXT VARCHAR2 (4000),
PRIMARY KEY (INDENTIFIER, LINE));
The identifier column is the foreign key to the original table. The Line is a simple integer (not a sequence) to keep the text fields in order. This allows keeping larger chunks of data
Yes this is not as efficient as a blob, clob, or LONG (I would avoid LONG fields if at all possible). Yes, this requires more mainenance, buf if your DBAs are dead set against managing CLOB fields in the database, this is option two.
EDIT:
My_Table below is where you currently have the VARCHAR column you are looking to expand. I would keep it in the table for the short text fields.
CREATE TABLE MY_TABLE (
INDENTIFER INT,
OTHER_FIELD VARCHAR2(10),
REQUIRED_TEXT VARCHAR(4000),
PRIMERY KEY (IDENTFIER));
Then write the query to pull the data join the two tables, ordering by LINE in the MY_TEXT field. Your application will need to split the string into 2000 character chunks and insert them in line order.
I would do this in a PL/SQL procedure. Both insert and select. PL/SQL VARCHAR strings can be up to 32K characters. Which may or may not be large enough for your needs.
But like every other person answering this question, I would strongly suggest making a case to the DBA to make the column a CLOB. From the program perspective this will be a BLOB and therefore simple to manage.
You said no BLOB or LONG... but what about CLOB? 4GB character data.
BLOB is the best solution. Anything else will be less convenient and a bigger maintenance annoyance.
Is BFILE a viable alternative datatype for your DBAs?
I don't get it. A CLOB is the appropriate database datatype. If your weird programming language will deal with strings of 8000 (or whatever) characters, what stops it writing those to a CLOB.
More specifically, what error do you get (from Oracle or your programming language) when you try to insert an 8000 character string into a column defined as a CLOB.

Characters spilled over multiple columns in Oracle 11g?

This is related to question: How to store unlimited characters in Oracle 11g?
If maximum I need is 8000 characters, can I just add 3 more varchar2 columns so that I will have 4 columns with 2000 char each to get 8000 chars. So when the first column is full, values would be spilled over to the next column and so on. Will this design have any bad side effects? Please suggest.
Why not just use a CLOB column instead? I read your other link, and I don't understand why your DBA's don't like these types of columns. I mean, CLOB is an important feature of Oracle just for this exact purpose. And your company paid good money for that feature when buying Oracle, so why not leverage Oracle to it's fullest capabilities instead of trying to come up with hacks to do something that the DB is not really designed to do?
Maybe instead of spending time trying to devise hacks to overcome limitations created by your DBAs, you should spend some time educating your DBA's on why CLOBs are the right feature to solve your problem.
I would never be satisfied with a bad design when the DB has the feature I need to make a good design. If the DBA's are the problem, then they need to change their viewpoint or you should go to senior level management in my opinion.
I agree with dcp that you should be using CLOB. But if against all sense you are forced to "roll your own" unlimited text using just VARCHAR2 columns then I would not do it by adding more and more VARCHAR2 columns to the table like this:
create table mytable
( id integer primary key
, text varchar2(2000)
, more_text varchar2(2000)
, and_still_more_text varchar2(2000)
);
Instead I would move the text to a separate child table like this:
create table mytable
( id integer primary key
);
create table mytable_text
( id references mytable(id)
, seqno integer
, text varchar2(2000)
, primary key (id, seqno)
);
Then you can insert as much text as you like for each mytable row, using many rows in mytable_text.
To add to DCP's and Tony's excellent answers:
You ask if the approach you are proposing will have any bad side effects. Here are a few things to consider:
Suppose you want to perform a search of your text data for a particular string. Your approach requires repeating the search on each column containing your text - results in a convoluted and inefficient WHERE clause.
Every time you want to expand your text field you have to add another column, which now means you have to modify every place you coded to do (1).
Everyone who has to maintain this structure after you will curse your name ;-)

Why does Char(1) change to Char(3) when copying over an Oracle DBLINK?

I have 2 databases, and I want to transport an existing table containing a CHAR column from database A to database B.
Database A is Oracle 9i, has encoding WE8ISO8859P1, and contains a table "foo" with at least 1 column of type CHAR(1 char). I can not change the table on database A because it is part of a third party setup.
Database B is my own Oracle 10g database, using encoding AL32UTF8 for all kinds of reasons, and I want to copy foo into this database.
I setup a database link from database B to database A. Then I issue the following command:
*create table bar as select * from #link#.foo;*
The data gets copied over nicely, but when I check the types of the columns, I notice that CHAR(1 char) has been converted into CHAR(3 char), and when querying the data in database B, it is all padded with spaces.
I think somewhere underwater, Oracle confuses it's own bytes and chars. CHAR(1 byte) is different from CHAR(1 char) etc. I've read about all that.
Why does the datatype change into a padded CHAR(3 char) and how do I stop Oracle from doing this?
Edit: It seems to have to do with transfering CHAR's between two specific patchlevels of Oracle 9 and 10. It looks like it is really a bug. as soon as I find out I'll post an update. Meanwhile: don't try to move CHAR's between databases like I described. VARCHAR2 works fine (tested).
Edit 2: I found the answer and posted it here: Why does Char(1) change to Char(3) when copying over an Oracle DBLINK?
Too bad I can not accept my own answer, because my problem is solved.
This problem is caused by the way Oracle (mis)handles character conversions between different character sets based on the original column length definition. When you define the size of a character type column in bytes, Oracle does not know how to do a conversion and bodges it. The solution is to always define the length of a character type in characters.
For a more in-depth explanation of the problem and how I figured this out have a look at
http://www.rolfje.com/2008/11/04/transporting-oracle-chars-over-a-dblink/
YOu need to learn the difference between the WE8ISO8859P1 NLS (which stores characters in one byte) and the AL32UTF8 which stores characters in up to four bytes. You will need to spend some quality time with the Oracle National Language Support (NLS) Documentation. Oracle automatically does the conversion through the database link, in an attempt to be helpful.
Try the following from your SQL prompt:
ALTER SESSION NLS_NCHAR WE8ISO8859P1
create table bar as select * from #link#.foo;
The first thing I would try is Creating the table NOT as a CTAS but with a list of column definitions and try to perform an insert of the first few thousand rows. If that didn't succeed then it would be very clear why... and you'd have quick confirmation that Thomas Low is dead on accurate.

Resources