Oracle: detect a NOT INMEMORY column - oracle

I have a table that has been created with a NOT INMEMORY column:
CREATE TABLE myTable (
foo VARCHAR2(20 BYTE) NOT NULL,
bar VARCHAR2(20 BYTE) NOT NULL,
baz VARCHAR2(2000 BYTE) NOT NULL,
);
ALTER TABLE myTable INMEMORY;
ALTER TABLE myTable NO INMEMORY ("baz") ;
What I need to do is identify the NO INMEMORY column by querying the static data dictionary views, but it appears all_tables, all_tab_columns and similar don't carry this information, and I can't find mention of one in the documentation. Is there a view which does?

You can use the ALL_TABLES and V$IM_COLUMN_LEVEL views to get the information. The information was found on Oracle-Base.
SQL> select inmemory from all_tables
2* where table_name = 'MYTABLE';
INMEMORY
___________
ENABLED
SQL> SELECT table_name,
2 segment_column_id,
3 column_name,
4 inmemory_compression
5 FROM v$im_column_level
6 WHERE table_name = 'MYTABLE'
7* ORDER BY segment_column_id;
TABLE_NAME SEGMENT_COLUMN_ID COLUMN_NAME INMEMORY_COMPRESSION
_____________ ____________________ ______________ _______________________
MYTABLE 1 FOO DEFAULT
MYTABLE 2 BAR DEFAULT
MYTABLE 3 BAZ NO INMEMORY

Related

Oracle column Datatype from metadata [duplicate]

I want to get the columns names and datatype and its datatype's length .as example
if there is a table
SQL> create table TestTable(
2 ID VARCHAR2(4) NOT NULL,
3 CODE Number(5),
4 MyDate DATE,
5 MyNumber Number(8,2))
I need something like in some_column to identify separately number(5) is for an integer and number(8,2) is for a desimal value...
I tried this
SELECT column_name, data_type, data_length FROM USER_TAB_COLUMNS WHERE table_name = 'some_table'
but this data_length gives me the length in byte so I can't figure out when there is a case like number(5) ,number(8,2)..what I need is like somthing below
TABLE_NAME COLUMN_NAME DATA_TYPE some_column
------------------------------ ------------------------------ --------------------------
TESTTABLE ID VARCHAR2 4
TESTTABLE MYNAME VARCHAR2 5
TESTTABLE MYDATE DATE -
TESTTABLE MYNUMBER NUMBER 8,2
help?
There are data_precision and data_scale columns there.
Please take a look at this example:
create table qwer(
x number,
y number(8,2),
z number(5,0),
a int,
b decimal(5,3)
);
SELECT column_name, data_type, data_precision, data_scale
FROM USER_TAB_COLUMNS
WHERE Table_name = 'QWER'
;
COLUMN_NAME DATA_TYPE DATA_PRECISION DATA_SCALE
------------- --------- -------------- ----------
B NUMBER 5 3
A NUMBER
X NUMBER
Y NUMBER 8 2
Z NUMBER 5 0
EDIT
To find primary key columns you need to join two dictionary views, please see the below example:
CREATE TABLE pk1(
id int primary key,
name varchar2(10)
);
CREATE TABLE pk2(
id int ,
pk1 number(10,0),
pk2 varchar2(5),
name varchar2(10),
constraint my_composite_pk primary key (id, pk1, pk2 )
);
SELECT c.table_name, cols.column_name, cols.position
FROM user_constraints c
JOIN USER_CONS_COLUMNS cols
USING ( CONSTRAINT_NAME )
WHERE c.table_name IN ('PK1', 'PK2' )
and c.constraint_type = 'P' /* P - means PRIMARY KEY */
ORDER BY 1,3
;
TABLE_NAME COLUMN_NAME POSITION
---------- ----------- ----------
PK1 ID 1
PK2 ID 1
PK2 PK1 2
PK2 PK2 3
If this is only for Geetting information then just Press ALT+F1 on the name of the table this will show you the names of the columns with length and data types.
Why don't you try SELECT * FROM information_schema.columns ?
It has columns "table_schema, table_name, column_name, ordinal_position, is_nullable, data_type, character_maximum_length, character_octet_length, numeric_precision, numeric_scale, datetime_precision", etc.

How to delete the primary key from without using constraint name

CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
How to remove the primary key as there is no constraint defined?
"How to remove PK as there is no constraint defined?"
Actually it's every bit as simple as you might hope:
SQL> create table t23 (id number primary key);
Table created.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C
------------------------------ -
SYS_C0034419 P
SQL> alter table t23 drop primary key;
Table altered.
SQL> select constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'T23'
4 /
no rows selected
SQL>
run this to get constraint name :
SELECT *
FROM user_cons_columns
WHERE table_name = Persons;
then run
ALTER TABLE Persons
DROP CONSTRAINT <pk constraint>;
Don't think you can do it in 1 SQL command,without knowing the constraint name, but you can know the constraint name as in this case it would be defined by system. Something which starts with SYS.....
Alternatively you can use a PLSQL block to achieve the same.
See the example below for your case.
CREATE TABLE Persons (
ID int PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
Find constraint name
select CONSTRAINT_NAME
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
OUTPUT:= SYS_C0012152
Drop Constraint
ALTER TABLE PERSONS
DROP CONSTRAINT SYS_C0012152;
Note: The constraint name SYS_C0012152 is not enclosed in single quotes.
PLSQL Block to do the same
declare
sql_stmt varchar2(255);
cons_name varchar2(30);
begin
select CONSTRAINT_NAME
into cons_name
From USER_CONSTRAINTS
where table_name='PERSONS'
AND CONSTRAINT_TYPE='P';
sql_stmt:=' ALTER TABLE PERSONS
DROP CONSTRAINT '||cons_name;
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt;
end;

How to select column value from a nested table

I created 1 object.
create type tab_billing as object(invoice_no number,
customername varchar2(100)
);
Now i created a table with the object as a column.
CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Is there anyway I can ONLY select invoice_no from the tab1.
select col2 from tab1;
Is givng me both invoice_no and customername. Substr function is not working here.
You can query the column value's object field directly, but to avoid confusing the object name resolution steps you have to supply and use a table alias:
select t1.col2.invoice_no from tab1 t1;
This is mentioned in the documentation:
To avoid inner capture and similar problems resolving references, Oracle Database requires you to use a table alias to qualify any dot-notational reference to subprograms or attributes of objects.
Qualifying the column with the the table name isn't enough; using select tab1.col2.invoice_no from tab1 gets ORA-00904. You have to use a table alias - although, slightly bizarrely, it still works if the alias is the same as the table name, so select tab1.col2.invoice_no from tab1 tab1 (i.e. aliasing tab1 as tab1, which is normally redundant) works too.
Quick demo:
create type tab_billing as object(invoice_no number,
customername varchar2(100)
);
/
Type TAB_BILLING compiled
CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Table TAB1 created.
insert into tab1 values (1, tab_billing(42, 'Test'));
1 row inserted.
select t1.col2.invoice_no from tab1 t1;
COL2.INVOICE_NO
---------------------------------------
42
You can use TREAT:
SQL> create type tab_billing as object(invoice_no number,
2 customername varchar2(100)
3 );
4 /
Type created.
SQL> CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Table created.
SQL> insert into tab1 values (1, tab_billing(10, 'ten')) ;
1 row created.
SQL> select col1,
2 TREAT(col2 AS tab_billing).invoice_no as invoice_no,
3 TREAT(col2 AS tab_billing).customername as customername
4 from tab1;
COL1 INVOICE_NO CUSTOMERNAME
------ ---------- --------------------
1 10 ten

In Oracle, does the unique constraint include an index implicitly?

this question is for performance issue,
For example, if I would add a unique constraint such as:
ALTER TABLE Staffs ADD CONSTRAINT test UNIQUE (Company_Name, Staff_ID);
should I add a unique index for performance issue?
CREATE UNIQUE INDEX test2 ON Staffs (Company_Name, Staff_ID);
For Primary key, I can see there must be a corresponding index in dba_indexes system table,
but I have not seen the equivalent for the case unique constraint
"I have not seen the equivalent for the case unique constraint"
Hmmmm, are you sure?
SQL> create table t23
2 (id number
3 , col1 date)
4 /
Table created.
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_UK UNIQUE
SQL>
Note that we can use an existing index, and it doesn't have to be unique. But this means the index name might not match the constraint name (this would also work for primary keys):
SQL> alter table t23 drop constraint t23_uk;
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
no rows selected
SQL> create index t23_idx on t23(id)
2 /
Index created.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_IDX NONUNIQUE
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL>
Does the non-unique index enforce the unique constraint? Yes it does:
SQL> insert into t23 values (1, sysdate)
2 /
1 row created.
SQL> r
1* insert into t23 values (1, sysdate)
insert into t23 values (1, sysdate)
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated
SQL> drop index t23_idx
2 /
drop index t23_idx
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
SQL>
We can check the data dictionary to see which index is associated with a constraint:
SQL> select constraint_name, constraint_type, index_name
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C INDEX_NAME
------------------------------ - ------------------------------
T23_UK U T23_IDX
SQL>

Oracle: how to drop a subpartition of a specific partition

I am using an oracle 11 table with interval partitioning and list subpartitioning like this (simplified):
CREATE TABLE LOG
(
ID NUMBER(15, 0) NOT NULL PRIMARY KEY
, MSG_TIME DATE NOT NULL
, MSG_NR VARCHAR2(16 BYTE)
) PARTITION BY RANGE (MSG_TIME) INTERVAL (NUMTOYMINTERVAL (1,'MONTH'))
SUBPARTITION BY LIST (MSG_NR)
SUBPARTITION TEMPLATE (
SUBPARTITION login VALUES ('FOO')
, SUBPARTITION others VALUES (DEFAULT)
)
(PARTITION oldvalues VALUES LESS THAN (TO_DATE('01-01-2010','DD-MM-YYYY')));
How do I drop a specific subpartitition for a specific month without knowing the (system generated) name of the subpartition? There is a syntax "alter table ... drop subpartition for (subpartition_key_value , ...)" but I don't see a way to specify the month for which I am deleting the subpartition. The partition administration guide does not give any examples, either. 8-}
You can use the metadata tables to get the specific subpartition name:
SQL> insert into log values (1, sysdate, 'FOO');
1 row(s) inserted.
SQL> SELECT p.partition_name, s.subpartition_name, p.high_value, s.high_value
2 FROM user_tab_partitions p
3 JOIN
4 user_tab_subpartitions s
5 ON s.table_name = p.table_name
6 AND s.partition_name = p.partition_name
7 AND p.table_name = 'LOG';
PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE HIGH_VALUE
--------------- ------------------ ------------ ----------
OLDVALUES OLDVALUES_OTHERS 2010-01-01 DEFAULT
OLDVALUES OLDVALUES_LOGIN 2010-01-01 'FOO'
SYS_P469754 SYS_SUBP469753 2012-10-01 DEFAULT
SYS_P469754 SYS_SUBP469752 2012-10-01 'FOO'
SQL> alter table log drop subpartition SYS_SUBP469752;
Table altered.
If you want to drop a partition dynamically, it can be tricky to find it with the ALL_TAB_SUBPARTITIONS view because the HIGH_VALUE column may not be simple to query. In that case you could use DBMS_ROWID to find the subpartition object_id of a given row:
SQL> insert into log values (4, sysdate, 'FOO');
1 row(s) inserted.
SQL> DECLARE
2 l_rowid_in ROWID;
3 l_rowid_type NUMBER;
4 l_object_number NUMBER;
5 l_relative_fno NUMBER;
6 l_block_number NUMBER;
7 l_row_number NUMBER;
8 BEGIN
9 SELECT rowid INTO l_rowid_in FROM log WHERE id = 4;
10 dbms_rowid.rowid_info(rowid_in =>l_rowid_in ,
11 rowid_type =>l_rowid_type ,
12 object_number =>l_object_number,
13 relative_fno =>l_relative_fno ,
14 block_number =>l_block_number ,
15 row_number =>l_row_number );
16 dbms_output.put_line('object_number ='||l_object_number);
17 END;
18 /
object_number =15838049
SQL> select object_name, subobject_name, object_type
2 from all_objects where object_id = '15838049';
OBJECT_NAME SUBOBJECT_NAME OBJECT_TYPE
--------------- --------------- ------------------
LOG SYS_SUBP469757 TABLE SUBPARTITION
As it turns out, the "subpartition for" syntax does indeed work, though that seems to be a secret Oracle does not want to tell you about. :-)
ALTER TABLE TB_LOG_MESSAGE DROP SUBPARTITION FOR
(TO_DATE('01.02.2010','DD.MM.YYYY'), 'FOO')
This deletes the subpartition that would contain MSG_TIME 2010/02/01 and MSG_NR FOO. (It is not necessary that there is an actual row with this exact MSG_TIME and MSG_NR. It throws an error if there is no such subpartition, though.)
Thanks for the post - it was very useful for me.
One observation though on the above script to identify the partition and delete it:
The object_id returned by dbms_rowid.rowid_info is not the object_id of the all_objects table. It is actually the data_object_id. It is observed that usually these ids match. However, after truncating the partitioned table several times, these ids diverged in my database. Hence it might be reasonable to instead use the data_object_id to find out the name of the partition:
select object_name, subobject_name, object_type
from all_objects where data_object_id = '15838049';
From the table description of ALL_OBJECTS:
OBJECT_ID Object number of the object
DATA_OBJECT_ID Object number of the segment which contains the object
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_rowid.htm
In the sample code provided in the above link, DBMS_ROWID.ROWID_OBJECT(row_id) is used instead to derive the same information that is given by dbms_rowid.rowid_info. However, the documentation around this sample mentions that it is a data object number from the ROWID.
Examples
This example returns the ROWID for a row in the EMP table, extracts
the data object number from the ROWID, using the ROWID_OBJECT function
in the DBMS_ROWID package, then displays the object number:
DECLARE object_no INTEGER; row_id ROWID; ... BEGIN
SELECT ROWID INTO row_id FROM emp
WHERE empno = 7499; object_no := DBMS_ROWID.ROWID_OBJECT(row_id); DBMS_OUTPUT.PUT_LINE('The obj. # is
'|| object_no); ...

Resources