How can I create a query to return the user columns that are referenced from an Oracle function-based index?
Eg. I create an index such as:
CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(MY_COL));
For non-function based indexes I just query ALL_IND_COLUMNS such as:
SELECT INDEX_NAME, COLUMN_NAME, COLUMN_POSITION
FROM ALL_IND_COLUMNS
WHERE INDEX_NAME = 'MY_INDEX'
However, this query returns COLUMN_NAME of a system generated column such as 'SYS_NC00012$' instead of the actual table column 'MY_COL' that the function-based index uses.
I know I can query DBMS_METADATA and read the returned index creation DDL
SELECT DBMS_METADATA.GET_DDL('INDEX', 'MY_INDEX') AS QUERY_STRING FROM DUAL
but this means I have to parse the function text which is not reliable for my purposes.
Therefore, can anyone please point me in the right direction as to how I can precisely determine which actual table columns a function-based index is defined upon?
SQL> Create table my_table ( my_col int);
Table Created;
SQL> CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(MY_COL));
Index Created
SQL> select
2 table_name c1,
3 index_name c2,
4 column_expression c3
5 from
6 dba_ind_expressions
7 where
8 table_name='MY_TABLE';
Table Index
name Name Expression
------------------------ ------------------------- ---------------------------------------
MY_TABLE MY_INDEX SQRT("MY_COL")
you can do some trick with "COMMENT ON COLUMN" , try this
Create table my_table ( my_col int);
CREATE INDEX MY_INDEX ON MY_TABLE (SQRT(my_col));
COMMENT ON COLUMN my_table.my_col IS 'MY_INDEX:my_col'; -- add your index:col
select * from ALL_COL_COMMENTS where table_NAME ='MY_TABLE'
you can use this trick function based index.
Related
How do I get all table names and its column names in oracle? The Table names should be printed first followed by all the column name, then the next table and its columns, and so on and so forth.
If you are dba you can see all tables in DB;
select * from all_tab_columns
order by table_name;
The query below, in the middle column (str), has the data the way you requested it. However, without the info in the first and/or the last column, it is not clear how you will know which values are table names and which are columns under them.
It would make a lot more sense to have table name in one column (repeated for each of its columns), then the column name and then the order. This would be just the second member of the union all operation.
The query below works for the tables in your schema. If you want to do this for all the tables you have access to, use all_tables and all_tab_columns; if you have DBA privileges, use dba_tables and dba_tab_columns (but in these cases, don't you need to know the schema/owner, not just the table name?)
select table_name as tbl, table_name as str, 0 as ord from user_tables
union all
select table_name, column_name, column_id from user_tab_columns
order by tbl, ord
;
SELECT table_name, column_name
FROM all_tab_cols
order by table_name, column_name
We have tables with range partitions of a month interval. The indexes on the tables including the primary key are local indexes.
However, when exchanging the partition from these tables with a table without partition, the local indexes become UNUSABLE. In the Oracle documentation, it only talks about issues with Global indexes. So we converted the global primary indexes to local by adding the partitioned key to the index.
Example queries -
CREATE TABLE sourcetable
(owner varchar2(30), OBJECT_NAME VARCHAR2(100))
PARTITION BY RANGE (owner)
(PARTITION P1 VALUES LESS THAN (MAXVALUE));
CREATE TABLE DESTTABLE
(owner varchar2(30), OBJECT_NAME VARCHAR2(100));
create index sourcetable_idx
on sourcetable ( owner )
local ;
alter table sourcetable add constraint src_pk primary key ( owner );
insert into sourcetable select U.OBJECT_ID, u.object_name from user_objects u
where rownum <11;
select index_name,partition_name,status from user_ind_partitions
where index_name IN (
select index_name from user_indexes
where table_name = 'SOURCETABLE'
);
The select gives the index status as
USABLE
ALTER TABLE sourcetable
EXCHANGE PARTITION p1 WITH TABLE desttable;
select index_name,partition_name,status from user_ind_partitions
where index_name IN (
select index_name from user_indexes
where table_name = 'SOURCETABLE'
);
The select on index status after exchanging the partition gives the index status as
UNUSABLE
We want to do online partition exchange. Is there any way we can do the exchange using statements like
UPDATE INDEXES
with the
EXCHANGE PARTITION
statement?
We tried using EXCHANGE statement with UPDATE INDEXES, but the indexes still became UNUSABLE.
ALTER TABLE sourcetable
EXCHANGE PARTITION p1 WITH TABLE desttable UPDATE INDEXES;
UPDATE INDEXES applies only for global indexes. Since you don't have any, this clause has no effect.
You must use INCLUDING INDEXES. However, for this you must create the same indexes on source and destination table. Try this one:
CREATE INDEX desttable_idx ON desttable ( OWNER );
ALTER TABLE sourcetable EXCHANGE PARTITION p1 WITH TABLE desttable INCLUDING INDEXES;
I am saving table ids as foreign key into another table using Oracle Apex Shuttle field like(3:4:5). Now I want to use these IDS in sql query using IN Clause. I have replaced : with , using replace function but it shows
no data found
message.
The following query works fine when I use static values.
select * from table where day_id IN(3,4,5)
But when I try to use
select * from table where id IN(Select id from table2)
it shows no data found.
From what i understand you have a list like 1:2:3:4 that you want to use in a IN clause; you can transform the list into separated values like this:
select regexp_substr('1:2:3:4','[^:]+', 1, level) as list from dual
connect by regexp_substr('1:2:3:4', '[^:]+', 1, level) is not null;
This will return:
List
1
2
3
4
Then you can simply add it to your query like this:
SELECT *
FROM TABLE
WHERE day_id IN
(SELECT regexp_substr('1:2:3:4','[^:]+', 1, level) AS list
FROM dual
CONNECT BY regexp_substr('1:2:3:4', '[^:]+', 1, level) IS NOT NULL
);
Can you try below statement. It has working as you expected.
create table table1 (id number, name varchar2(20));
alter table table1 add constraints pri_cons primary key(id);
create table table2 (id number, name varchar2(20));
alter table table2 add constraints ref_cons FOREIGN KEY(id) REFERENCES table1 (id);
begin
insert into table1 values (1,'Bala');
insert into table1 values (2,'Sathish');
insert into table1 values (3,'Subbu');
insert into table2 values (1,'Nalini');
insert into table2 values (2,'Sangeetha');
insert into table2 values (3,'Rubini');
end;
/
select * from table1 where id IN (Select id from table2);
Is there is a way to remove a constraint (unique index) based on columns name?
What I would like to do is to remove a constraint where columna name is name, and name_type.
ALTER TABLE MY_TABLE DROP CONSTRAINT NAME_OF_CONSTRAINT;
I don't have a name so I would like to do it this way...
ALTER TABLE MY_TABLE DROP CONSTRAINT **WHERE COLUMN = col1 AND column = col2**
Any syntax to do something like this on a constraint.
I didn't think this was possible with a single statement, but it turns out it is, as shown in the examples in the documentation:
ALTER TABLE MY_TABLE DROP UNIQUE(col1, col2);
A complete example:
ALTER TABLE MY_TABLE ADD UNIQUE (col1, col2);
Table my_table altered.
SELECT CONSTRAINT_NAME, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'MY_TABLE';
CONSTRAINT_NAME INDEX_NAME
------------------------------ ------------------------------
SYS_C0092455 SYS_C0092455
ALTER TABLE MY_TABLE DROP UNIQUE(col1, col2);
Table my_table altered.
SELECT CONSTRAINT_NAME, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'MY_TABLE';
no rows selected
An alternative approach is to query the USER_CONSTRAINTS and USER_CONS_COLUMNS views to find the matching constraint name - presumably system-generated or you would already know it - and then use that name. If you need to do this as a script then you could query in a PL/SQL block, and plug the found constraint name into a dynamic ALTER TABLE statement.
Do a SELECT * FROM USER_CONS_COLUMNS or ALL_CONS_COLUMNS. This will give you the constraint name for the owner, table and column combination.
Out of the multiple rows returned for a column name, use the constraint names as necessary in the ALTER TABLE ... DROP CONSTRAINT... syntax.
Use dynamic sql to do it for all rows in a loop if you are absolutely sure that you can drop all of them.
This will give you an extra layer of protection so that you don't accidentally drop a constraint that was needed.
Why an entry is created in user_tab_cols when we create a function based on a column of a table?
create table t1(a varchar2(100), b number);
select * from user_tab_cols where table_name = 'T1'; -- Two rows coming
create index idx1 on t1(upper(a));
select * from user_tab_cols where table_name = 'T1'; -- Three rows coming
What is the reason to put an entry in user_tab_cols?
The extra column is a virtual column that Oracle has added to store the value of the indexed expression. From the Oracle documentation:
Oracle Database represents the index expression as a virtual column
You can easily verify in SQL*Plus that the extra column is virtual. In fact, it is also a 'hidden' column:
SQL> select column_name, hidden_column, virtual_column from user_tab_cols where table_name = 'T1';
COLUMN_NAME HID VIR
------------------------------ --- ---
A NO NO
B NO NO
SYS_NC00003$ YES YES
The name of the virtual column may be different on your machine.
user_tab_columns filters out hidden columns, as explained in the Oracle documentation for user_tab_cols. So, if you don't wish to see this column, you can query user_tab_columns instead of user_tab_cols:
SQL> select column_name from user_tab_columns where table_name = 'T1';
COLUMN_NAME
------------------------------
A
B
SQL>