Postgresql and oracle with greater than operator behaviour - oracle

I have a table called names with database entries Rm, RM, Rnash, Rmash. In addition I am using PostgreSQL 9.1 and Oracle 11.
In Oracle the following query
select *
from names
where name > 'Rm'
returns Rnash, Rmash. However in PostgreSQL the same query returns RM. The ASCII value of M in RM is less than m in Rm.
Question 1: Why does PostgreSQL query return RM? Both Oracle and PostgreSQL are case-sensitive database.
My guess is that it might be due to COLLATE mismatch in PostgreSQL.
Question 2: How do I find COLLATE information related to PostgreSQL and Oracle?
Question 3: What do I have to do to make the output from the PostgreSQL query the same as Oracle's?
Thanks for your help in Advance.

It's because your locale's collation rules specify case-insensitive sorting.
Check the LC_COLLATE setting on your database. Look at \l+ mydatabase in psql or SHOW lc_collate;.
If you want to sort on the character ordinal alone, without national language collation rules being applied, use COLLATE "C", e.g.
select *
from names
where name > 'Rm' COLLATE "C"
If you want to use "dumb" character-ordinal sorting by default for all operations you'll need to re-create the database with the option LC_COLLATE "C" to CREATE DATABASE. This will involve a dump and reload.
You can instead ALTER TABLE ... ALTER COLUMN mycolumn TYPE thesametype COLLATE "C" to change the default collation for a particular column. Leave the type the same as it was before, and just append COLLATE "C".

Related

Oracle backup with SEQUENCE-ID Column

Good morning,
I allready know how to do oracle backups with expdp and impdp. It is also no problem for me to remap backups from one schema to an other.
But know I have something where I find no solution to solve it.
I have a table with an ID column. This column has a default value based on a sequence.
CREATE TABLE "TABLE_NAME"
( "ID" NUMBER(*,0) DEFAULT "TABLE_NAME_ID_SEQ"."NEXTVAL",
"KEY" VARCHAR2(200 BYTE),
"VALUE" CLOB
)
After executing thise statement Oracle defines this default with "MY_USER"."TABLE_NAME_ID_SEQ"."NEXTVAL".
This is not an issue until I try to uses the backup with a different schema name. The REMAP_SCHEMA parameter of impdp seems only to change the schema definition in the tabelnames but not in the default values. So the imported backup creates a table with a default values which references to a wrong schema.
How could I solve this?
Best regards"

set schema_search_path does not work with sequencs in h2

Script
drop schema vending if exists cascade;
drop schema joblog if exists cascade;
drop schema conditions if exists cascade;
create schema if not exists vending;
create schema if not exists joblog;
create schema if not exists conditions;
set schema_search_path vending,joblog,conditions;
set schema joblog;
create sequence job_log_id_seq;
select nextval('JOBLOG.JOB_LOG_ID_SEQ');
select nextval('JOB_LOG_ID_SEQ');
only the last statement doesn't work.
Save as h2_bug.sql and run with
H2JAR=~/.m2/repository/com/h2database/h2/1.4.199/h2-1.4.199.jar
java -cp $H2JAR org.h2.tools.RunScript -url jdbc:h2:~/tmp/h2_bug -script h2_bug.sql
All statements from your script work properly in H2 1.4.199.
NEXTVAL is a legacy compatibility-only function, you shouldn't use it in H2. It actually doesn't use schema search path and the last command works only because the sequence was found in the current schema. The proper method to fetch sequence values in H2 is a standard NEXT VALUE FOR [schemaName.]sequenceName expression. VALUES NEXT VALUE FOR JOB_LOG_ID_SEQ; will check schema search path after the current schema, unlike function that you use.
It's rarely appropriate to use the sequence directly, in the most cases identity columns should be used (ID BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY or something like it), but you may have own reasons to use the sequence, for example, if you really need to generate the value before row insertion.

Oracle change column type from CLOB to NCLOB

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.

Best way to add column with default value while under load

When adding a column to a table that has a default value and a constraint of not null. Is it better to run as a single statement or to break it into steps while the database is under load.
ALTER TABLE user ADD country VARCHAR2(4) DEFAULT 'GB' NOT NULL
VERSUS
ALTER TABLE user ADD country VARCHAR2(2)
UPDATE user SET country = 'GB'
COMMIT
ALTER TABLE user MODIFY country DEFAULT 'GB' NOT NULL
Performance depends on the Oracle version you use. Locks are generated anyway.
If version <= Oracle 11.1 then #1 does the same as #2. It is slow anyway.
Beginning with Oracle 11.2, Oracle introduced a great optimization for the first statement (one command doing it all). You don't need to change the command - Oracle just behaves differently. It stores the default value only in data dictionary instead of updating each physical row.
But I also have to say, that I encountered some bugs in the past related to this feature (in Oracle 11.2.0.1)
failure of traditional import if export was done with direct=Y
merge statement can throw an ORA-600 [13013] (internal oracle error)
a performance problem in queries using such tables
I think this issues are fixed in current version 11.2.0.3, so I can recommend to use this feature.
Some time ago we have evaluated possible solutions of the same problem. On our project we had to remove all indexes on table, perform altering and restore indexes back.
If your system needs to be using the table then DBMS_Redefinition is really your only choice.

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