Get details from System Catalog in Oracle 11G - oracle

I need to find the following information on all user defined tables in a SINGLE query in Oracle11g:
Table name
Column name
Constraint name
Constraint type - Use 'PK', 'FK', 'CK' and 'NN' instead of 1 letter codes
Search Condition for any Check (CK) constraints
Table and Column that each FK references
So far, I have managed this:
SELECT table_name FROM user_tables ORDER BY table_name;
TABLE_NAME
---------------
CLIENT
EMPLOYEE
FAULTREPORT
OUTLET
RAGREEMENT
VEHICLE
SELECT table_name, constraint_name, constraint_type
FROM user_constraints
WHERE table_name IN ('CLIENT','EMPLOYEE','FAULTREPORT','OUTLET','RAGREEMENT','VEHICLE')
ORDER BY table_name;
TABLE_NAME CONSTRAINT_NAME C SEARCH_CONDITION
--------------- ------------------------------ - --------------------------------------------------------------------------------
CLIENT CLIENT_CLIENTNAME_NN C clientName IS NOT NULL
CLIENT CLIENT_STREET_NN C street IS NOT NULL
CLIENT CLIENT_CITY_NN C city IS NOT NULL
CLIENT CLIENT_STATE_NN C state IS NOT NULL
CLIENT CLIENT_EMAIL_CK C REGEXP_LIKE(email,'^[A-Z0-9._%-]+#[A-Z0-9.-]+\.[A-Z]{2,}$','i') AND email IS NOT
NULL
CLIENT CLIENT_PHONE_CK C REGEXP_LIKE(phone,'^(\(\d{3}\))([[:blank:]])\d{3}-\d{4}$|^\d{3}(-)\d{3}(-)\d{4}$
|^\d{10}$')
AND phone IS NOT NULL
CLIENT CLIENT_CLIENTNO_PK P
EMPLOYEE EMPLOYEE_LNAME_NN C lname IS NOT NULL
EMPLOYEE EMPLOYEE_NUM_PK P
EMPLOYEE EMPLOYEE_OUTLET_NUM_FK R
EMPLOYEE EMPLOYEE_FNAME_NN C fname IS NOT NULL
EMPLOYEE EMPLOYEE_DOB_CK C hireDate >= ADD_MONTHS(dob, 216)
EMPLOYEE EMPLOYEE_PHONE_CK C REGEXP_LIKE(phone,'^(\(\d{3}\))([[:blank:]])\d{3}-\d{4}$|^\d{3}(-)\d{3}(-)\d{4}$
|^\d{10}$')
AND phone IS NOT NULL
EMPLOYEE EMPLOYEE_GENDER_CK C gender in ('MALE', 'FEMALE')
FAULTREPORT FAULTREPORT_DATECHECKED_NN C dateChecked IS NOT NULL
FAULTREPORT FAULTREPORT_REPORTNUM_PK P
FAULTREPORT FAULTREPORT_EMPLOYEE_NUM_FK R
FAULTREPORT FAULTREPORT_RENTAL_NUM_FK R
FAULTREPORT FAULTREPORT_LICENSENO_NN C licenseNo IS NOT NULL
OUTLET OUTLET_STREET_NN C street IS NOT NULL
OUTLET OUTLET_NUM_PK P
OUTLET OUTLET_STATE_NN C state IS NOT NULL
OUTLET OUTLET_ZIPCODE_NN C zipCode IS NOT NULL
OUTLET OUTLET_PHONE_CK C REGEXP_LIKE(phone,'^(\(\d{3}\))([[:blank:]])\d{3}-\d{4}$|^\d{3}(-)\d{3}(-)\d{4}$
|^\d{10}$')
AND phone IS NOT NULL
OUTLET OUTLET_CITY_NN C city IS NOT NULL
OUTLET OUTLET_MGR_NUM_FK R
RAGREEMENT RAGREEMENT_CLIENT_NUM_FK R
RAGREEMENT RAGREEMENT_LICENSE_NUM_FK R
RAGREEMENT RAGREEMENT_MILEAGE_CK C mileagebefore < mileageafter
RAGREEMENT RAGREEMENT_INSURANCETYPE_NN C insurancetype IS NOT NULL
RAGREEMENT RAGREEMENT_PK P
RAGREEMENT RAGREEMENT_STARTDATE_NN C startdate IS NOT NULL
RAGREEMENT RAGREEMENT_MILEAGEBEFORE_NN C mileagebefore IS NOT NULL
VEHICLE VEHICLE_DAILYRATE_NN C dailyrate IS NOT NULL
VEHICLE VEHICLE_MODEL_NN C model IS NOT NULL
VEHICLE VEHICLE_MAKE_NN C make IS NOT NULL
VEHICLE SYS_C0010620 C "LICENSENO" IS NOT NULL
VEHICLE VEHICLE_LICENSE_NUM_PK P
VEHICLE VEHICLE_YEAR_CK C EXTRACT(YEAR FROM year) > 2005 AND year IS NOT NULL
VEHICLE VEHICLE_OUT_NUM_FK R
40 rows selected.
Can someone help me out? Thanks!

Well, you could simply use
SELECT table_name, constraint_name, constraint_type
FROM user_constraints
WHERE table_name IN (SELECT table_name FROM user_tables)
ORDER BY table_name;
or
SELECT UT.table_name, UC.constraint_name, UC.constraint_type
FROM user_tables UT
INNER JOIN user_constraints UC ON UT.table_name = UC. table_name
ORDER BY UT.table_name;
This will give you details about all the tables you own.
Now, if you want the details about all tables your account has access to, you can use
SELECT table_name, constraint_name, constraint_type
FROM user_constraints
WHERE table_name IN (SELECT table_name FROM all_tables)
ORDER BY table_name;
or
SELECT AT.table_name, UC.constraint_name, UC.constraint_type
FROM all_tables AT
INNER JOIN user_constraints UC ON AT.table_name = UC. table_name
ORDER BY AT.table_name;
EDITED : If you want to see all column names and the constraint details if any, use the below (untested)
SELECT UTC.table_name
, UTC.column_name
, UC.constraint_name
, UC.constraint_type
FROM USER_TAB_COLUMNS UTC
LEFT JOIN user_constraints UC ON UTC.table_name = UC. table_name
ORDER BY UTC.table_name;

Related

Oracle porting natural JOIN

I am reviewing code written by a previous colleague. It uses a "natural join", which I am unfamiliar with and never used.
I would like to change this into JOIN inner, outer, left….. whatever the correct equivalent is, which shows what is actually being joined.
Below is my test case. Any help would be greatly appreciated.
create table holidays(
holiday_date DATE not null,
holiday_name VARCHAR2(20),
constraint holidays_pk primary key (holiday_date),
constraint is_midnight check ( holiday_date = trunc ( holiday_date ) )
);
INSERT into holidays (HOLIDAY_DATE,HOLIDAY_NAME)
WITH dts as (
select to_date('25-NOV-2021 00:00:00','DD-MON-YYYY HH24:MI:SS'), 'Thanksgiving 2021' from dual union all
select to_date('29-NOV-2021 00:00:00','DD-MON-YYYY HH24:MI:SS'), 'Hanukkah 2021' from dual
)
SELECT * from dts;
SELECT constraint_name, constraint_type, column_name
from user_constraints natural join user_cons_columns
where table_name = 'HOLIDAYS';
CONSTRAINT_NAME CONSTRAINT_TYPE COLUMN_NAME
SYS_C0075523509 C HOLIDAY_DATE
IS_MIDNIGHT C HOLIDAY_DATE
HOLIDAYS_PK P HOLIDAY_DATE
In a natural join, Oracle creates an "implicit" join clause based on common column names. If you want to switch to inner join, you'll have to do it yourself.
Natural:
SQL> SELECT constraint_name, constraint_type, column_name
2 from user_constraints natural join user_cons_columns
3 where table_name = 'EMP';
CONSTRAINT_NAME C COLUMN_NAME
------------------------------ - --------------------
SYS_C00105284 C EMPNO
PK_EMP P EMPNO
Which columns are common? Let's see:
SQL> select column_name from all_tab_columns where table_name = 'USER_CONSTRAINTS'
2 intersect
3 select column_name from all_tab_columns where table_name = 'USER_CONS_COLUMNS';
COLUMN_NAME
--------------------
CONSTRAINT_NAME
OWNER
TABLE_NAME
SQL>
Inner:
SQL> SELECT a.constraint_name, a.constraint_type, b.column_name
2 from user_constraints a join user_cons_columns b
3 on a.constraint_name = b.constraint_name
4 and a.owner = b.owner
5 and a.table_name = b.table_name
6 where a.table_name = 'EMP';
CONSTRAINT_NAME C COLUMN_NAME
------------------------------ - --------------------
SYS_C00105284 C EMPNO
PK_EMP P EMPNO
SQL>
OK, but - we know better. As we're querying user_cons... views, they contain data we own so we don't really need an owner. Moreover, constraint names are unique within a single schema, so we don't need table_name either. Therefore, this would do:
SQL> SELECT a.constraint_name, a.constraint_type, b.column_name
2 from user_constraints a join user_cons_columns b on a.constraint_name = b.constraint_name
3 where a.table_name = 'EMP';
CONSTRAINT_NAME C COLUMN_NAME
------------------------------ - --------------------
SYS_C00105284 C EMPNO
PK_EMP P EMPNO
SQL>

how to get full tables and columns with relations or not in ORACLE

How can I do to (left)join user_tab_columns with user_cons_columns and user_constraints to get the result below:
Table, Column, SourceTable, SourceColumn
ORDER, ORDER_ID, null, null
ORDER, ORDER_DATE, null, null
ORDER, ORDER_CLIENT, CLIENT, CLIENT_ID
CLIENT, CLIENT_ID, null, null
ORDER_DETAIL, ORDER_ID, ORDER, ORDER_ID
ORDER_DETAIL, PRODUCT_ID, PRODUCT, PRODUCT_ID
PRODUCT PRODUCT_ID, null, null
So... I need all table and columns but once a column is a foreign key,
I need to know the table and the column (primary key) related.
Slight edits to linked answer:
List of foreign keys and the tables they reference
all_ to user sources.
Course you could just use all and then filter on owner.
SELECT a.table_name, a.column_name, a.constraint_name, c.owner,
c.r_owner, c_pk.table_name r_table_name, c_pk.constraint_name r_pk
FROM user_cons_columns a
LEFT JOIN user_constraints c
ON a.owner = c.owner
AND a.constraint_name = c.constraint_name
LEFT JOIN user_constraints c_pk
ON c.r_owner = c_pk.owner
AND c.r_constraint_name = c_pk.constraint_name
WHERE c.constraint_type = 'R'
--AND a.table_name = :TableName
check following query :
select a.table_name,c1.column_name,b.table_name,c2.column_name from USER_constraints a,USER_constraints b,user_cons_columns c1,user_cons_columns c2
where a.r_constraint_name = b.constraint_name and a.table_name = c1.table_name and b.table_name = c2.table_name if you just need FK constraint use a.constraint_type ='R' in where clouse.

ORA-01427 while UPDATE self-join ORACLE

two tables, each has employee_id and manager_id which links to employee_id Tables have different employee_id.
UPDATE employee u
SET u.manager_id = (SELECT m.id
FROM employee e
JOIN old_db.employees oe ON e.last_name = oe.last_name
JOIN old_db.employees om ON oe.manager_id = om.employee_id
INNER JOIN employee m ON m.last_name = om.last_name
WHERE e.id = u.id)
WHERE manager_id IS NULL;
gives
ERROR at line 2:
ORA-01427: single-row subquery returns more than one row
I've tried rownum=1 but this makes all manager_id same.
Select query with one given employee_id returns one value
SQL> SELECT m.id
2 FROM employee e
3 JOIN old_db.employees oe ON e.last_name = oe.last_name
4 JOIN old_db.employees om ON oe.manager_id = om.employee_id
5 INNER JOIN employee m ON m.last_name = om.last_name
6 WHERE e.id = 1805;
ID
----------
1804
Well the root cause of problem is in table employees or in table employee last_name are not unique. And when you join table on last name you get more then one row. You may check it with next query:
SELECT e.id, count(*), count(distinct m.id)
FROM employee e
JOIN old_db.employees oe ON e.last_name = oe.last_name
JOIN old_db.employees om ON oe.manager_id = om.employee_id
INNER JOIN employee m ON m.last_name = om.last_name
GROUP BY e.id;
May be exists more suitable column to join it for example employee_id if so you query may be rewritten to:
UPDATE employee u
SET u.manager_id = (SELECT oe.manager_id
FROM old_db.employees oe
WHERE oe.employee_id = u.id)
WHERE manager_id IS NULL;

Oracle select random rows matching a join condition

My objective is simple, I have to create a temporary table with some random values from a employee table whenever the department is in some particular department (say 2). For the rest of departments I don't care the value, it can be NULL.
Currently I have the following :
create table test
as
select s.DEPTNAME,
cast (
(case when s.DEPTID in (2) then
(SELECT a.ENAME FROM
(SELECT b.ENAME, b.DEPTID FROM EMPLOYEE b
WHERE b.DEPTID IS NOT NULL
ORDER BY DBMS_RANDOM.VALUE) a
WHERE a.DEPTID = s.DEPTID AND ROWNUM = 1
)
END)
AS VARCHAR2(30)) "ENAME" from DEPARTMENT s;
But the main issue here is related to performance. For every department value in 2 we do a sort of EMPLOYEE table to get a single random ENAME.
Is there a better way to do this ? I know sample might work but I want to achieve more randomness.
First idea - join randomly numbered enames:
with
e as (select ename, deptid, row_number() over (order by dbms_random.value) rn
from employee where deptid = 2),
c as (select count(1) cnt from e),
d as (select deptname, deptid, round(dbms_random.value(1, c.cnt)) rn from department, c)
select d.deptname, e.ename from d left join e using (rn, deptid)
SQLFiddle demo
Second possible solution, which worked for me, is to create function returning random ename from table employee
and use it in your query, but it would be probably slower.
Edit - according to comment:
If, for some reason, the first part of your statement is "fixed", then you could use this syntax:
create table test as
select deptname, ename from (
with
e as (select ename, deptid, row_number() over (order by dbms_random.value) rn
from employee where deptid = 2),
c as (select count(1) cnt from e),
d as (select deptname, deptid, round(dbms_random.value(1, c.cnt)) rn
from department cross join c)
select d.deptname, e.ename from d left join e using (rn, deptid));

List of table which don't have a primary key

Need to get the list of tables name from a schema which doesn't have a primary key. I tried the following query to get this, but it will list all other keys except primary keys.
SELECT a.constraint_name,a.table_name
FROM ALL_CONS_COLUMNS A
JOIN ALL_CONSTRAINTS C
ON A.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
C.CONSTRAINT_TYPE not in('P')
and a.owner ='my_schema';
If you only want this for the current user, it's better to user the user_xxx views instead of the all_xxx views.
The following should do what you want:
select ut.table_name
from user_tables ut
where not exists (select 1
from user_constraints ac
where ac.table_name = ut.table_name
and ac.constraint_type = 'P'
);
If you do need this for a different user, then you can use the following.
select at.*
from all_tables at
where not exists (select 1
from all_constraints ac
where ac.owner = at.owner
and ac.table_name = at.table_name
and ac.constraint_type = 'P'
)
and at.owner = 'MY_SCHEMA';
Don't forget that Oracle is case sensitive and that user names are stored in uppercase, so a.owner ='my_schema' will most probably not return anything.
Another way:
select owner,table_name
from all_tables
where owner = 'my_schema'
MINUS
select owner,table_name
from all_constraints
where owner = 'my_schema'
and constraint_type = 'P'
Try like this,
SELECT table_name
FROM all_tables A
WHERE table_name NOT IN
(
SELECT table_name
FROM all_constraints WHERE constraint_type ='P'
)
AND a.owner = 'my_schema';
Select tables.owner || ‘.’ ||
tables.table_name
as table_owner
From all_tables tables,
(Select
owner,
TABLE_NAME,
constraint_type,
CONSTRAINT_NAME
FROM ALL_CONSTRAINTS
WHERE CONSTRAINT_TYPE = ‘P’ /* list of all tables with PK */
) constr
Where tables.owner = constr.owner (+)
And tables.table_name = constr.table_name (+)
and tables.owner <> ‘SYS’
and tables.owner <> ‘SYSTEM’
And constr.owner IS NULL
And constr.table_name IS NULL
ORDER BY 1

Resources