Oracle all foreign key references - oracle

I've inherited a schema so don't have complete knowledge/confidence in what is there.
I have a project table with a projectId. There are a whole bunch of other tables that reference this table by project id. What I want to do is run a query to establish:
Which tables have foreign key references to the project table on
the project id
Which tables have a column called project id (in
case foreign keys are not set up).
If it was SQL Server I know how to query the metadata but how do I do this in Oracle?

1)
select table_name
from all_constraints
where r_constraint_name = [your pk/uk constraint on PROJECTS(id)]
2)
select table_name
from all_tab_columns
where column_name = 'PROJECT_ID'
You may want to add an extra predicate containing the OWNER column.
Regards,
Rob.

Ok. Here a request that give you the referenced table and column :
SELECT
c_list.CONSTRAINT_NAME as NAME,
substr(c_src.COLUMN_NAME, 1, 20) as SRC_COLUMN,
c_dest.TABLE_NAME as DEST_TABLE,
substr(c_dest.COLUMN_NAME, 1, 20) as DEST_COLUMN
FROM ALL_CONSTRAINTS c_list, ALL_CONS_COLUMNS c_src, ALL_CONS_COLUMNS c_dest
WHERE c_list.CONSTRAINT_NAME = c_src.CONSTRAINT_NAME
AND c_list.OWNER = c_src.OWNER
AND c_list.R_CONSTRAINT_NAME = c_dest.CONSTRAINT_NAME
AND c_list.OWNER = c_dest.OWNER
AND c_list.CONSTRAINT_TYPE = 'R'
AND c_src.OWNER = '<your-schema-here>'
AND c_src.TABLE_NAME = '<your-table-here>'
GROUP BY c_list.CONSTRAINT_NAME, c_src.TABLE_NAME,
c_src.COLUMN_NAME, c_dest.TABLE_NAME, c_dest.COLUMN_NAME;
Which give you something like this:
NAME |SRC_COLUMN |DEST_TABLE | DEST_COLUMN
----------------------|----------------|----------------------|-----------
CFK_RUB_FOR |FOR_URN |T03_FORMAT |FOR_URN
CFK_RUB_RUB |RUB_RUB_URN |T01_RUBRIQUE |RUB_URN
CFK_RUB_SUP |SUP_URN |T01_SUPPORT |SUP_URN
CFK_RUB_PRD |PRD_URN |T05_PRODUIT |PRD_URN
You can forget the substr() function if the result is usable without. This is not my case.

1): SELECT * FROM USER_CONSTRAINTS WHERE CONSTRAINT_NAME='R' and R_CONSTRAINT_NAME='xxx'
where xxx is the name of the primary key constraint on the project table
2): SELECT * FROM USER_TAB_COLUMNS WHERE COLUMN_NAME='PROJECT_ID'

The r_constraint_name answers here didn't seem to work for me, not sure why as I'm new to Oracle myself, but this worked:
SELECT * FROM ALL_CONSTRAINTS WHERE CONSTRAINT_NAME = '<constraint>';

My problem was slightly different. I have a table and I wanted to programatically know which other tables/columns it references.
I started with Stan's response above but this didn't give me exactly what I needed, so I came up with this, which I post here in case anyone else has my problem:
WITH src as
(SELECT ac.table_name, ac.constraint_name, accs.column_name, accs.position, ac.r_constraint_name
FROM ALL_CONSTRAINTS ac, all_cons_columns accs
WHERE ac.owner = '<owner>'
AND ac.constraint_type = 'R'
AND ac.table_name = '<src_table>'
AND accs.owner = ac.owner
AND accs.table_name = ac.table_name
AND accs.constraint_name = ac.constraint_name
ORDER BY ac.table_name, ac.constraint_name, accs.position),
dst as
(SELECT ac.table_name, ac.constraint_name, accs.column_name, accs.position
FROM ALL_CONSTRAINTS ac, all_cons_columns accs
WHERE ac.owner = '<owner>'
AND accs.owner = ac.owner
AND accs.table_name = ac.table_name
AND accs.constraint_name = ac.constraint_name
ORDER BY ac.table_name, ac.constraint_name, accs.position)
SELECT src.table_name as src_table,
dst.table_name as dst_table,
src.constraint_name as src_constraint,
src.column_name as src_column,
dst.column_name as dst_column,
src.position as position
FROM src,dst
WHERE src.r_constraint_name = dst.constraint_name
AND src.position = dst.position

Use this query.
select b.TABLE_NAME,b.CONSTRAINT_NAME ,a.COLUMN_NAME
from all_constraints b, all_cons_columns a
where r_constraint_name = 'Constraint_Name' and a.CONSTRAINT_NAME=b.CONSTRAINT_NAME;

Related

Column name is not passed to PostgreSQL on JDBC Scan in Apache Drill

While trying to run SQL query for PostgreSQL, instead of the column names from the table referred it it pushing down * to the database.
select
m.m_id,
cnt_c_no
from (
select
m_id
from pg_test_main.test1.table1
where
last_date >= '2019-01-01 00:00:00'
) as m
left join (
select
ci.m_id,
count(ci.c_no) as cnt_c_no
from (
select
m_id,
c_no
from pg_test.public.table2
) as ci
inner join (
select
c_no
from pg_test.public.table3
where
is_del = 'F'
) as c on ci.c_no = c.c_no
group by
ci.m_id
) as join1 on m.m_id = join1.m_id;
00-00 Screen
00-01 Project(m_id=[$0], cnt_c_no=[$1])
00-02 Project(m_id=[$0], cnt_c_no=[$2])
00-03 HashJoin(condition=[=($0, $1)], joinType=[left], semi-join: =[false])
00-05 Jdbc(sql=[SELECT "m_id" FROM "test1"."table1" WHERE "last_date" >= '2019-01-01 00:00:00' ])
00-04 Project(m_id0=[$0], cnt_c_no=[$1])
00-06 HashAgg(group=[{0}], cnt_c_no=[COUNT($1)])
00-07 Project(m_id=[$0], c_no=[$1])
00-08 HashJoin(condition=[=($1, $2)], joinType=[inner], semi-join: =[false])
00-10 Project(m_id=[$3], c_no=[$1])
00-12 Jdbc(sql=[SELECT * FROM "public"."table2" ])
00-09 Project(c_no0=[$0])
00-11 Project(c_no=[$0])
00-13 SelectionVectorRemover
00-14 Filter(condition=[=($60, 'F')])
00-15 Jdbc(sql=[SELECT * FROM "public"."table3" ])
As you can see, Jdbc Scan for table1 was using column names.
but, Jdbc Scan for table2 and table3 was not using column names. It pushed down * to the database.
How can I control jdbc scan so that it can push down colume names?
Apache Drill version is 1.16.0 (embedded-mode)
I tried to reproduce it with MySQL on both Drill 1.17 and Drill 1.15, but for the query, similar to the query you have specified, all the query is pushed into the JDBC storage:
SELECT m.person_id,
cnt_c_no
FROM
(SELECT person_id
FROM mysql.`drill_mysql_test1`.person1
WHERE date_field >= '2019-01-01 00:00:00') AS m
LEFT JOIN
(SELECT ci.person_id,
count(ci.last_name) AS cnt_c_no
FROM
(SELECT person_id,
last_name
FROM mysql.`drill_mysql_test`.person) AS ci
INNER JOIN
(SELECT last_name
FROM mysql.`drill_mysql_test`.person2
WHERE boolean_field = 'F' ) AS c ON ci.last_name = c.last_name
GROUP BY ci.person_id) AS join1 ON m.person_id = join1.person_id
The plan for this query:
00-00 Screen
00-01 Project(person_id=[$0], cnt_c_no=[$1])
00-02 Jdbc(sql=[SELECT `t0`.`person_id`, `t5`.`cnt_c_no` FROM (SELECT `person_id` FROM `drill_mysql_test1`.`person1` WHERE `date_field` >= '2019-01-01 00:00:00') AS `t0` LEFT JOIN (SELECT `t1`.`person_id`, COUNT(`t1`.`last_name`) AS `cnt_c_no` FROM (SELECT `person_id`, `last_name` FROM `drill_mysql_test`.`person`) AS `t1` INNER JOIN (SELECT `last_name` FROM `drill_mysql_test`.`person2` WHERE `boolean_field` = 'F') AS `t3` ON `t1`.`last_name` = `t3`.`last_name` GROUP BY `t1`.`person_id`) AS `t5` ON `t0`.`person_id` = `t5`.`person_id` ])
Could you please provide CTAS for Postgres tables, so I will try to reproduce it again with specific data types. Also, if possible, please check whether this issue is still reproduced on Drill 1.17.
UPD:
Comment under this answer helped to discover that this problem was caused by the following issue: https://issues.apache.org/jira/browse/DRILL-7340 and it will be resolved in Drill 1.18.0.

Ordering columns by Primary Key position in PostgreSQL

I am new to PostgreSQL and was wondering if there is a table which matches Oracle's user_cons_columns table which provides a column position column similar to user_cons_columns.position. Essentially, I am trying to convert the following oracle code to PostgreSQL. It attains the PK columns in order of PK definition:
Oracle Code (Original):
select a.table_name tab_name,
a.colum_name col_name,
a.position col_order
from user_cons_columns a,
user_constraints b
where a.table_name = b.table_name
and a.constraint_name = b.constraint_name
and b.constraint_type = 'P'
and a.table_name = 'some_table_name';
PostgreSQL Code (Oracle Equiv):
/* Below is my attempt at the PostgreSQL conversion */
select isc.table_name tab_name,
isc.column_name col_name,
isc.ordinal_position col_order
from pg_attribute as pga
inner join pg_class as pgc on pga.attrelid = pgc.oid
inner join pg_namespace as pgn on pgn.oid = pgc.relnamespace
inner join information_schema.columns as isc on isc.column_name = pga.attname
and isc.table_name = pgc.relname
where isc.table_name = 'sometablename';
In my PostgreSQL conversion attempt I am missing the relationship between the constraint and its position but use the column position. Which is not the same. Is there a way to do the former? Thanks in advance!
The column numbers of a constraint and their order are stored in pg_constraint.conkey; for foreign keys, the corresponding numbers of the target columns are in pg_constraint.confkey.
The description of table columns is in pg_attribute; the column number is stored in attnum.
Below is the solution that I derived thanks to the answer from #Laurenz Albe.
select isc.table_name tab_name,
isc.col_name col_name,
pgco.conkey[1] col_order
from pg_attribute as pga
inner join pg_class as pgc on pga.attrelid = pgc.oid
inner join pg_namespace as pgn on pgn.oid = pgc.relnamespace
inner join information_schema.columns as isc on isc.column = pga.attname
and isc.table_name = pgc.relname
inner join pg_constraint as pgco on pgco.conkey[1] = pga.attnum
and pgco.connamespace = pgc.relnamespace
and pgco.conrelid = pga.attrelid
where isc.table_name = 'sometablename'
and pgco.contype ='p';
Hope this is useful to someone else.

Update oracle query issue with Join

I dont understand why its giving Sql Command not properly ended,
Update Table1
Set LS.SECU_CHECKER_CODE = '1000',
LS.SECU_CHECKER_DATE = To_Char(SysDate, 'YYYYMMDDHH24MISS'),
LS.SECU_RECORD_STATUS = 98
From Table1 LS
Join Table2 LS2
On LS2.SECC_SECURITY_ID = LS.SECU_SECURITY_ID
Where LS2.SECC_LIMIT_ID = '00010101010101';
The syntax for updating from a view is different in Oracle from the syntax you are using. However, you shouldn't even update from a view in your case, because you are not using the other table's content, but merely check for existence of a record for which you should rather use EXISTS or IN:
update table1
set secu_checker_code = '1000'
, secu_checker_date = to_char(sysdate, 'yyyymmddhh24miss')
, secu_record_status = 98
where secu_security_id in
(
select secc_security_id
from table2
where secc_limit_id = '00010101010101'
);
It looks like you are trying to update a selection of table 1. You need a where clause.
Possibly something like this:
update table1 t1
set ls.secu_checker_code = '1000'
,ls.secu_checker_date = to_char(sysdate, 'YYYYMMDDHH24MISS')
,ls.secu_record_status = 98
where t1.secu_security_id in (select t2.secc_security_id
from table2 t2
where t2.secc_limit_id = '00010101010101');
This is also working fine
UPDATE table1
SET (SECU_CHECKER_CODE,
SECU_CHECKER_DATE,
SECU_RECORD_STATUS) = (
Select '1000',
To_Date(SysDate),
98
From table1
Join table2
On SECC_SECURITY_ID = SECU_SECURITY_ID
Where SECC_LIMIT_ID = '00010101010101')

Yii2 Oracle performance

I use Yii2 a lot but normally with MySQL. This is my first time using it with Oracle. I am finding the performance quite poor though. I've done some googling around and see that although it doesn't appear that common to use Yii2 + Oracle there does seem to be people talking about it being quite slow.
I'm wondering what advice/tips/processes/packages can be employed to improve performance?
I am loading a very small table. It has 8 rows, the entire table has 4 columns. They're are 27 DB calls using 6.4MB of data, that takes about 3 seconds to run. Looking at the logs I see a lot of stuff I don't really understand:
SELECT D.CONSTRAINT_NAME, D.CONSTRAINT_TYPE, C.COLUMN_NAME, C.POSITION, D.R_CONSTRAINT_NAME, E.TABLE_NAME AS TABLE_REF, F.COLUMN_NAME AS COLUMN_REF, C.TABLE_NAME
FROM
ALL_CONS_COLUMNS C
INNER JOIN ALL_CONSTRAINTS D ON D.OWNER = C.OWNER AND D.CONSTRAINT_NAME = C.CONSTRAINT_NAME
LEFT JOIN ALL_CONSTRAINTS E ON E.OWNER = D.R_OWNER AND E.CONSTRAINT_NAME = D.R_CONSTRAINT_NAME
LEFT JOIN ALL_CONS_COLUMNS F ON F.OWNER = E.OWNER AND F.CONSTRAINT_NAME = E.CONSTRAINT_NAME AND F.POSITION = C.POSITION
and
SELECT a.column_name, a.data_type, a.data_precision, a.data_scale, a.data_length,
a.nullable, a.data_default,
( SELECT D.constraint_type
FROM ALL_CONS_COLUMNS C
inner join ALL_constraints D on D.OWNER = C.OWNER and D.constraint_name = C.constraint_name
WHERE C.OWNER = B.OWNER
and C.table_name = B.object_name
and C.column_name = A.column_name
and D.constraint_type = 'P') as Key,
com.comments as column_comment
FROM ALL_TAB_COLUMNS A
inner join ALL_OBJECTS B ON b.owner = a.owner and ltrim(B.OBJECT_NAME) = ltrim(A.TABLE_NAME)
LEFT JOIN all_col_comments com ON (A.owner = com.owner AND A.table_name = com.table_name AND A.column_name = com.column_name)
Then more stuff about triggers.
I also get errors when I try to use relations such as
Model::find()->with('relationName')->all();
I get
'ORA-01795: maximum number of expressions in a list is 1000 error.
These tables collectively have about 17k rows. There's about 11k in one table and about 7k in the other that are linked.
I'm using fk constraints as references within the tables.
Add/Use following settings in your database configurations.
'schemaCacheDuration' => 7200,
'schemaCache' => 'cache',
'enableSchemaCache' => true,
And
change YII_DEBUG from true to false and YII_ENV from dev to prod.
This will reduce unnecessary SQL executions.

Displaying foreign key relationships in Oracle 9i

Is there a command in oracle 9i that displays the foreign keys of a table and also the table that those foreign keys reference?
I was searching, did not find anything but i found an equivalent command that works with MySql which is SHOW CREATE TABLE
Is there an equivalent command for this within oracle's SQL?
I appreciate your response, however I thought there was a really short way of doing this like MySql.
Here's another answer: The dbms_metadata package has a function that can return the DDL for a table definition.
SELECT dbms_metadata.get_ddl('TABLE', '<table>', '<schema>') FROM dual;
This package has apparently been available since Oracle 9.2
http://download-west.oracle.com/docs/cd/B10501_01/appdev.920/a96612/d_metada.htm#1656
You could start by listing all of the constraints for the table along with any referenced constraint on other tables:
SELECT
acc.table_name
,acc.column_name
,acc.constraint_name
,ac.r_constraint_name AS referenced_constraint
FROM all_cons_columns acc
INNER JOIN all_constraints ac ON (acc.constraint_name = ac.constraint_name)
WHERE acc.table_name = UPPER('your_table_here');
If you have sensible naming conventions for your constraints it should be possible to identify which are the foreign keys, an 'FK' prefix/suffix is typical.
This may do what you want, it uses Oracle system views. I don't have an Oracle instance handy to test it, however.
SELECT fk.owner, fk.constraint_name, fk.table_name, fc.column_name,
pk.owner, pk.constraint_name, pk.table_name, pc.column_name
FROM all_constraints fk
JOIN all_cons_columns fc ON (fk.owner = fc.owner AND fk.constraint_name = fc.constraint_name)
JOIN (all_constraints pk
JOIN all_cons_columns pc ON (pk.owner = pc.owner AND pk.constraint_name = pc.constraint_name))
ON (fk.r_owner = pk.owner AND fk.r_constraint_name = pk.constraint_name
AND fc.position = pc.position)
WHERE fk.constraint_type = 'R' AND pk.constraint_type IN ('P', 'U')
AND fk.owner = '<schema>' AND fk.table_name = '<table>';
If you need the DDL for the foreign keys in the future, then here is the answer in advance :)
select
DBMS_METADATA.GET_DEPENDENT_DDL('REF_CONSTRAINT' ,atb.table_name, atb.owner)
from
all_tables atb, all_constraints ac
where
atb.owner = ac.owner and
ac.constraint_type = 'R' and
ac.table_name = atb.table_name and
atb.owner = 'YOURSCHEMA';

Resources