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

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);

Related

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.

NUM_ROWS in DBA_TABLES not reflected upon metadata sharing

In Oracle 12c, I have a table created with sharing = metadata. Following are the sql statements:
create table fedcommusr.md_commtab1 sharing=metadata
(deptno number, dname varchar2(100));
insert into fedcommusr.md_commtab1 values (1, 'One');
insert into fedcommusr.md_commtab1 values (2, 'Two');
comment on column fedcommusr.md_commtab1.deptno is 'department number';
comment on column fedcommusr.md_commtab1.dname is 'Department name is';
Executed the DBMS_STATS as follows:
exec DBMS_STATS.GATHER_SCHEMA_STATS(ownname=>'FEDCOMMUSR');
Following is the query executed to obtain the num_rows
select owner,table_name, NUM_ROWS from dba_tables where owner like upper('%fed%') ;
and output is as follows:
FEDCOMMUSR MD_COMMTAB1 (null)
Why are the num_rows not updated ?
In 12.2 latest RU I tested and have no problem: stats gathered and visible on application root as well as application PDB.
You can trace statistics gathering with dbms_stats.set_global_prefs('trace',1+4) and set serveroutput on to show it.
Regards,
Franck.

Oracle - exchange partitions with a table

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.

Replacing certain lines in a statemement

I am exporting ddl statemements for tables using dbms_metadata.set_transform_param package. This works as intended. However, I am also interested to remove a certain lines from the output.
For example: here is the output of one of the tables:
CREATE TABLE "FREEZES"
( "PLAYER_ID" NUMBER(9,0) NOT NULL ENABLE,
"PRODUCT_ID" NUMBER(19,0)
)
TABLESPACE "MINE" ;
ALTER TABLE "FREEZES" ADD CONSTRAINT "FREEZES_U" UNIQUE ("PLAYER_ID", "PRODUCT_ID")
USING INDEX
TABLESPACE "MINE_IDX" ENABLE;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (FOREIGN KEY) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (UNIQUE INDEX) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
What I would like to have is:
CREATE TABLE "FREEZES"
( "PLAYER_ID" NUMBER(9,0) NOT NULL ENABLE,
"PRODUCT_ID" NUMBER(19,0)
)
TABLESPACE "MINE" ;
ALTER TABLE "FREEZES" ADD CONSTRAINT "FREEZES_U" UNIQUE ("PLAYER_ID", "PRODUCT_ID")
USING INDEX
TABLESPACE "MINE_IDX" ENABLE;
And here is the query I am using:
SELECT dbms_metadata.get_ddl(object_type, object_name, owner) as object_ddl
from dba_objects where owner = 'MINE' and object_type = 'TABLE';
I do know that I have to use regular expressions, something like:
SELECT regexp_replace(dbms_metadata.get_ddl(object_type, object_name, owner), 'pattren') as object_ddl
from dba_objects where owner = 'MINE' and object_type = 'TABLE';

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