Oracle - exchange partitions with a table - oracle

I try to create a table2 on Oracle 11g.2.0.3 with:
CREATE table2
LOGGING TABLESPACE TS_table1_2014 PCTFREE 10 INITRANS 1 STORAGE ( INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS UNLIMITED BUFFER_POOL DEFAULT ) NOCOMPRESS
as (select * from table1 where date_text <= '2015-12-31');
and I have received error below when I try to exchange this table2 with a partitioned table3:
alter table table3 exchange partition partition_name WITH TABLE table2;
Error report -
SQL Error: ORA-14097: column type or size mismatch in ALTER TABLE EXCHANGE PARTITION
14097. 00000 - "column type or size mismatch in ALTER TABLE EXCHANGE PARTITION"
*Cause: The corresponding columns in the tables specified in the
ALTER TABLE EXCHANGE PARTITION are of different type or size
*Action: Ensure that the two tables have the same number of columns
with the same type and size.
I have test diferences with query below:
Select a.COLUMN_NAME
, a.DATA_TYPE, b.DATA_TYPE
, a.data_length, b.data_length
, a.data_precision, b.data_precision
, a.data_scale, b.data_scale
, a.nullable, b.nullable
from ALL_TAB_COLUMNS a
full outer join ALL_TAB_COLUMNS b on a.column_name=b.column_name
and b.owner=user and b.table_name='&table2'
where a.owner=user and a.table_name='&table1'
and (
nvl(a.data_type,'#')!=nvl(b.data_type,'#')
or nvl(a.data_length,-1)!=nvl(b.data_length,-1)
or nvl(a.data_precision,-100)!=nvl(b.data_precision,-100)
or nvl(a.data_scale,-100)!=nvl(b.data_scale,-100)
or nvl(a.nullable,'#')!=nvl(b.nullable,'#')
)
;
Some differences resulted are in a column size. This syntax "create as select" didn't keep order and size for new table created.
How can I create table2 as select from table1 with force keep same size columns as primary table1 source?
Thanks!

I can't find any differences in your DDL. What I suggest is to use the same DDL to create table2, then do:
insert into table2 select * from table1;

You need to use dbms_metadata package or query number of data dictionary views like all_tab_columns and etc to get metadata about existing table so you can construct correct sql for swap-table (used in exchange partition operation). CTAS does not transfer DEFAULT values for example and constraints except NOT NULL checks.
The best practice is to create/re-create/modify this table simultaneously with partitioned table.

Related

Rowid not in order when insert into an oracle table

first,I create a table
create table TEST
(
id VARCHAR2(11),
name VARCHAR2(11)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64K
next 1M
minextents 1
maxextents unlimited
);
Then I insert ,delete ,insert some data,and watch the result:
truncate table test;
insert into test values (1,1);
commit;
insert into test values (2,1);
commit;
insert into test values (3,1);
commit;
delete test where id = 2;
commit;
insert into test values (4,1);
commit;
insert into test values (5,1);
commit;
insert into test values (6,1);
commit;
delete test where id = 5;
commit;
insert into test values (7,1);
commit;
insert into test values (8,1);
commit;
insert into test values (9,1);
commit;
select t.*, t.rowid from TEST t
then I can see the query result is :
"ID","NAME","ROWID"
"1","1","AAAGXqAAEAAAAP+AAA"
"8","1","AAAGXqAAEAAAAP+AAB"
"3","1","AAAGXqAAEAAAAP+AAC"
"4","1","AAAGXqAAEAAAAP+AAD"
"6","1","AAAGXqAAEAAAAP+AAE"
"7","1","AAAGXqAAEAAAAP+AAF"
"9","1","AAAGXqAAEAAAAP+AAG"
You can see the second line is 8,but I insert 8 after 7,it should appear after 7.Seems the order of the rowid is not same as the order of the insertion.
So in my real project,I insert the last data,but it do not appear at last,but jump to the middle space,then my customer can not find the last data.
My question is, the order of rowid can not be guaranteed when insert data,right?Or I must add an order field?
There is no internal order to a SQL table, in the sense that when Oracle executes your query, it is free to return records in any order whatsoever. The way to impose an order to the result set is to add an ORDER BY clause to your query, e.g.
SELECT t.*, t.rowid
FROM TEST t
ORDER BY t.ID;
Don't rely on ROWID as it can be changed. For example, if you export schema and then import it back, ROWID might change so - if your code relies on (wrong) assumption that it is constant - code will break and you'll have a problem.
Use something else as an identifier and a value to sort rows in a table. For example, a sequence.

Oracle: Understanding and replicating ORA-14130 UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITION

everyone!
I'm facing this error (ORA-14130 UNIQUE constraints mismatch in ALTER TABLE EXCHANGE PARTITION) on my shared development environment and I can't fix it just because I don't completely understand it.
Let's create these three tables:
What index/constraint should I create on which table for the ALTER TABLE EXCHANGE PARTITION fails with ORA-14130?
CREATE TABLE TMP_DEBUG_BORRAR_DATOS_1 AS
SELECT level id, timestamp'2000-11-02 09:00:00' fecha
FROM dual
CONNECT BY level <= 100000 ;
CREATE TABLE TMP_DEBUG_BORRAR_DATOS_2 AS
SELECT level id, timestamp'2001-09-10 13:00:00' fecha
FROM dual
CONNECT BY level <= 100000 ;
CREATE TABLE TMP_DEBUG_BORRAR_TEST
(
id,
fecha
)
PARTITION BY RANGE ( fecha )
(
PARTITION year_2000 VALUES LESS THAN ( timestamp'2000-12-02 00:00:00' ),
PARTITION year_2001 VALUES LESS THAN ( timestamp'2001-10-10 00:00:00' )
)
AS
SELECT 1, timestamp'2000-11-02 09:00:00'
FROM dual
WHERE 1=0;
--What should I add here for the ALTER TABLE EXCHANGE PARTITION to throw an ORA-14130?
ALTER TABLE TMP_DEBUG_BORRAR_TEST EXCHANGE PARTITION year_2000 WITH table TMP_DEBUG_BORRAR_DATOS_1;
Thank u SO much!
you need to have a unique constraint on the partition table to get the error. So, do this before the exchange:
alter table TMP_DEBUG_BORRAR_TEST add constraint ukk unique (id, fecha);
and then you need to do the exchange like this:
ALTER TABLE TMP_DEBUG_BORRAR_TEST EXCHANGE PARTITION year_2000 WITH table TMP_DEBUG_BORRAR_DATOS_1 including indexes;

Right way to create index organized table

I am trying to create a index organized table in oracle 11. I create the index organized table and insert the row from another table.
create table salIOT (
mypk ,
cid ,
date,
CONSTRAINT sal_pk PRIMARY KEY (mypk)
) ORGANIZATION INDEX
AS Select * from another table;
But the leaf blocks are empty when I query
SQL> Select owner, index_name, table_name, leaf_blocks from all_indexes where table_name like 'SALIOT';
Am I missing something here?
You still need to gather statistics on the table, something like:
exec dbms_stats.gather_table_stats('ABC', 'IOTTableName')
(assuming 'ABC' is your username; change as needed) - then re-run your SELECT against ALL_INDEXES and you will see how many leaf blocks you have.

Table tablespace shown as X but appears to be 'Users'

I am using SQL*Plus to create a table with the following sql:
CREATE TABLE SCHEMA_OWNER.TEST_TABLE (
ID NUMBER(19,0) NOT NULL,
TEST_STRING VARCHAR2(255 CHAR),
PRIMARY KEY (ID)
);
When I try and do an insert with any user into that table, I see the following error:
INSERT INTO TEST_TABLE (ID, TEST_STRING) values (1, 'Test')
ORA-01950: no privileges on tablespace 'USERS'
This implies that the table has been created in the Users tablespace, but when I look in the USER_TABLES table, I see that the tablespace is the same as all of the other tables, and not 'Users':
SELECT table_name, tablespace_name from USER_TABLES;
TABLE_NAME TABLESPACE_NAME
---------------- ---------------
TABLE1 DATA_TABLESPACE
TEST_TABLE DATA_TABLESPACE
When I create the table in SQL developer using the same SQL, I don't have any errors when inserting data.
1) Why am I getting this error when the table isn't in the Users tablespace?
2) Why am I only getting it when running the sql script from SQL*Plus?
Thanks to Aleksej for suggesting it could be an issue with the indexes. The problem was that when I was creating the index on the table, I wasn't creating it for the schema owner, which meant that it was being created in a different tablespace.
So instead of
CREATE INDEX TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);
I needed to do
CREATE INDEX SCHEMA_OWNER.TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);

shrinking a column in oracle

Lets say i have a table with the following definition
create table dummy (col1 number(9) not null)
All the values in this dummy.col1 are 7 digit long. Now i want to reduce the length of this column from 9 - 7 using alter command. Oracle gives me error that column to be modified must be empty to decrease precision or scale. Makes sense.
I want to ask is there any work around to reduce the column size?
I can't delete the values in the column.
I can't copy values from this column to another since it has trillions of data.
The column size has no relationship to how the data is physically stored (they are variable length)
e.g. '23' in a number(2) will take exactly the same space if stored in a number(38)
It is purely a constraint on the maximum number that can be stored in the column therefore you could just add a constraint on the column:
ALTER TABLE dummy ADD
CONSTRAINT c1
CHECK (col1 < 9999999)
ENABLE
VALIDATE;
if you want it to go a little quicker change VALIDATE to NOVALIDATE obviously this will not check the validity of the existing data.
Kevin's answer is excellent.
The only other way to do it is to
rename the existing column,
create a new column with the old name and the new size,
issue an update statement to populate the new field (which you said you cannot do)
and then drop the renamed column.
Are you sure you cannot find some downtime one weekend to perform this task ?
Solution #1
My solution below keeps the original column order.
I found that to be important, especially if there are canned SQL statements out
there (middle tier, client tier) that point back to your database that do implicit
SELECTs.
i.e.
SELECT *
FROM tableName
WHERE ...;
INSERT INTO copyTableName(column1,column2,column3,...)
SELECT *
FROM tableName
WHERE ...;
Here goes:
Generate the DDLs for
1. The table containing the column you intend to resize
2. All the relationship constraints, indexes, check constraints, triggers that reference that table.
3. All the foreign keys of other tables that reference the primary key of this table.
Make sure each table-referencing-object DDL is stand-alone, separate from the
CREATE TABLE DDL.
You'll have something like
/* 1. The table containing the column you intend to resize */
CREATE TABLE tableName
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(size) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Copy out just the CREATE TABLE statement, change the table name and
reduce the size of the column you wish to modify:
CREATE TABLE tableName_YYYYMMDD
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(reducedSize) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
Insert the data from tableName into tableName_YYYYMMDD:
INSERT /* APPEND */ INTO tableName_YYYYMMDD(
column1 ,
column2 ,
column3 ,
... )
SELECT
column1 ,
column2 ,
column3 ,
...
FROM tableName;
COMMIT;
Drop all objects referencing the original table.
Also, drop all foreign keys that reference the tableName primary key pkName.
Don't worry, you've saved the DDL so you'll be able to recreate them.
Notice that I drop indexes after copying the data out of tableName.
I do this because perhaps one of the indexes will be used in the
above SELECT so that operation will complete faster.
DROP INDEX indexName ;
DROP INDEX compositeIndexName ;
DROP UNIQUE INDEX pkName ;
ALTER TABLE tableName DROP CONSTRAINT pkName ;
ALTER TABLE tableName DROP CONSTRAINT fkName ;
ALTER TABLE otherTableName DROP CONSTRAINT otherTableFkName ;
Drop the original table.
DROP TABLE tableName;
Rename the new table.
ALTER TABLE tableName_YYYYMMDD RENAME TO tableName;
Recreate all referencing objects from the DDL statements you saved before.
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Solution #2
Keep the column order but do not rebuild non-unique-used-by-PK indexes that might contain column2.
ALTER TABLE tableName ADD (column2Copy TYPE(reducedSize));
UPDATE tableName SET column2Copy = column2;
ALTER TABLE tableName MODIFY (column2 TYPE(size) NULL);
ALTER TABLE tableName DROP CONSTRAINT pkName;
DROP INDEX pkName;
UPDATE tableName SET column2 = null;
ALTER TABLE tableName MODIFY (column2 TYPE(reducedSize));
UPDATE tableName SET column2 = column2Copy;
ALTER TABLE tableName DROP COLUMN column2Copy;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
COMMIT;

Resources