Ordering columns by Primary Key position in PostgreSQL - oracle

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.

Related

Error when running a sub query in Oracle SQL

I am trying to join three tables using a sub query.
The result of the first left outer join is to be used with another table to get a composite view with all attributes.
I am getting an error where the compile says, Unknown Command for the table in the second join clause.
When I create two independent views and then join then it works fine.
(select
l.ENROLLED_CONTENT,
l.LEARNING_ENROLLMENT_LEARNER,
l.EMPLOYEE_ID,
l.JOB_FAMILY_GROUP,
l.EMPLOYEE_TYPE,
l.JOB_FAMILY,
l.LEARNING_ENROLLMENT,
l.COMPLETION_STATUS,
l.COMPLETION_DATE,
l.EXPIRATION_DATE,
l.CF_LRV_LEARNING_CONTENT_NUMBER,
l.LEARNING_CONTENT_DETAIL,
l.LEARNING_CONTENT_TYPE,
l.LESSON_TYPE,
e.id# "WK_WORKER_ID"
from tgt_workday.learning l
left outer join ods_hrmaster.employee e
on l.EMPLOYEE_ID = e.employee#) t1
left outer join ( select
per_ids_id,
per_id,
id_pureid from
ods_pure.person_ids
) t2 on t1.wk_worker_id = t2.value where t2.type = 'Employee ID';
You can write it in a simple way. There is no need to make sub-queries as:
SELECT L.ENROLLED_CONTENT,
L.LEARNING_ENROLLMENT_LEARNER,
L.EMPLOYEE_ID,
L.JOB_FAMILY_GROUP,
L.EMPLOYEE_TYPE,
L.JOB_FAMILY,
L.LEARNING_ENROLLMENT,
L.COMPLETION_STATUS,
L.COMPLETION_DATE,
L.EXPIRATION_DATE,
L.CF_LRV_LEARNING_CONTENT_NUMBER,
L.LEARNING_CONTENT_DETAIL,
L.LEARNING_CONTENT_TYPE,
L.LESSON_TYPE,
E.ID# "WK_WORKER_ID"
FROM TGT_WORKDAY.LEARNING L
LEFT OUTER JOIN ODS_HRMASTER.EMPLOYEE E
ON L.EMPLOYEE_ID = E.EMPLOYEE#
LEFT OUTER JOIN ODS_PURE.PERSON_IDS T2
ON E.ID# = T2.VALUE
AND T2.TYPE = 'Employee ID';
Once you use the outer joined table's column in WHERE clause, It will result in the same result as inner join(there is another ways to use it in WHERE clause though). So it is better to avoid using outer joined table's column in the WHERE clause.
Try as
SELECT *
FROM ( (SELECT l.ENROLLED_CONTENT,
l.LEARNING_ENROLLMENT_LEARNER,
l.EMPLOYEE_ID,
l.JOB_FAMILY_GROUP,
l.EMPLOYEE_TYPE,
l.JOB_FAMILY,
l.LEARNING_ENROLLMENT,
l.COMPLETION_STATUS,
l.COMPLETION_DATE,
l.EXPIRATION_DATE,
l.CF_LRV_LEARNING_CONTENT_NUMBER,
l.LEARNING_CONTENT_DETAIL,
l.LEARNING_CONTENT_TYPE,
l.LESSON_TYPE,
e.id# "WK_WORKER_ID"
FROM tgt_workday.learning l
LEFT OUTER JOIN ods_hrmaster.employee e
ON l.EMPLOYEE_ID = e.employee) t1
LEFT OUTER JOIN
(SELECT per_ids_id, per_id, id_pureid FROM ods_pure.person_ids) t2
ON t1.wk_worker_id = t2.VAL AND t2.TYPE = 'Employee ID')

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.

Find if a column in Oracle has a sequence

I am attempting to figure out if a column in Oracle is populated from a sequence. My impression of how Oracle handles sequencing is that the sequence and column are separate entities and one needs to either manually insert the next sequence value like:
insert into tbl1 values(someseq.nextval, 'test')
or put it into a table trigger. Meaning that it is non-trivial to tell if a column is populated from a sequence. Is that correct? Any ideas about how I might go about figuring out if a column is populated from a sequence?
You are correct; the sequence is separate from the table, and a single sequence can be used to populate any table, and the values in a column in some table may mostly come from a sequence (or set of sequences), except for the values manually generated.
In other words, there is no mandatory connection between a column and a sequence - and therefore no way to discover such a relationship from the schema.
Ultimately, the analysis will be of the source code of all applications that insert or update data in the table. Nothing else is guaranteed. You can reduce the scope of the search if there is a stored procedure that is the only way to make modifications to the table, or if there is a trigger that sets the value, or other such things. But the general solution is the 'non-solution' of 'analyze the source'.
If the sequence is used in a trigger, it is possible to find which tables it populates:
SQL> select t.table_name, d.referenced_name as sequence_name
2 from user_triggers t
3 join user_dependencies d
4 on d.name = t.trigger_name
5 where d.referenced_type = 'SEQUENCE'
6 and d.type = 'TRIGGER'
7 /
TABLE_NAME SEQUENCE_NAME
------------------------------ ------------------------------
EMP EMPNO_SEQ
SQL>
You can vary this query to find stored procedures, etc that make use of the sequence.
There are no direct metadata links between Oracle sequences and any use in the database. You could make an intelligent guess if a column's values are related to a sequence by querying the USER_SEQUENCES metadata and comparing the LAST_NUMBER column to the data for the column.
select t.table_name,
d.referenced_name as sequence_name,
d.REFERENCED_OWNER as "OWNER",
c.COLUMN_NAME
from user_trigger_cols t, user_dependencies d, user_tab_cols c
where d.name = t.trigger_name
and t.TABLE_NAME = c.TABLE_NAME
and t.COLUMN_NAME = c.COLUMN_NAME
and d.referenced_type = 'SEQUENCE'
and d.type = 'TRIGGER'
As Jonathan pointed out: there is no direct way to relate both objects. However, if you "keep a standard" for primary keys and sequences/triggers you could find out by finding the primary key and then associate the constraint to the table sequence.
I was in need of something similar since we are building a multi-db product and I tried to replicate some classes with properties found in a DataTable object from .Net which has AutoIncrement, IncrementSeed and IncrementStep which can only be found in the sequences.
So, as I said, if you, for your tables, use a PK and always have a sequence associated with a trigger for inserts on a table then this may come handy:
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE = 'P'
union all
select tc.table_name,
case tc.nullable
when 'Y' then 1
else 0
end as is_nullable,
case ac.constraint_type
when 'P' then 1
else 0
end as is_identity,
ac.constraint_type,
seq.increment_by as auto_increment_seed,
seq.min_value as auto_increment_step,
com.comments as caption,
tc.column_name,
tc.data_type,
tc.data_default as default_value,
tc.data_length as max_length,
tc.column_id,
tc.data_precision as precision,
tc.data_scale as scale
from SYS.all_tab_columns tc
left outer join SYS.all_col_comments com
on (tc.column_name = com.column_name and tc.table_name = com.table_name)
LEFT OUTER JOIN SYS.ALL_CONS_COLUMNS CC
on (tc.table_name = cc.table_name and tc.column_name = cc.column_name and tc.owner = cc.owner)
LEFT OUTER JOIN SYS.ALL_CONSTRAINTS AC
ON (ac.constraint_name = cc.constraint_name and ac.owner = cc.owner)
LEFT outer join user_triggers trg
on (ac.table_name = trg.table_name and ac.owner = trg.table_owner)
LEFT outer join user_dependencies dep
on (trg.trigger_name = dep.name and dep.referenced_type='SEQUENCE' and dep.type='TRIGGER')
LEFT outer join user_sequences seq
on (seq.sequence_name = dep.referenced_name)
where tc.table_name = 'TABLE_NAME'
and tc.owner = 'SCHEMA_NAME'
AND AC.CONSTRAINT_TYPE is null;
That would give you the list of columns for a schema/table with:
Table name
If column is nullable
Constraint type (only for PK's)
Increment seed (from the sequence)
Increment step (from the sequence)
Column comments
Column name, of course :)
Data type
Default value, if any
Length of column
Index (column id)
Precision (for numbers)
Scale (for numbers)
I'm pretty sure that code can be optimized but it works for me, I use it to "load metadata" for tables and then represent that metadata as entities on my frontend.
Note that I'm filtering only primary keys and not retrieving compound key constraints since I don't care about those. If you do you'll have to modify the code to do so and make sure that you filter duplicates since you could get one column twice (one for the PK constraint, another for the compound key).

collation conflict

Is there any one who knows how we can solve collation issue in select linq query?
I'm getting this error when I want to select data in linq.
Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Latin1_General_CI_AS" in the equal to operation
var lstData = from s in dataTrackDB.datas
join b in dataTrackDB.brandDatas on i.brandcode equals b.brandcode
join b in dataTrackDB.brandDatas on i.brandcode equals b.brandcode
join b in dataTrackDB.brandDatas on i.brandcode equals b.brandcode
join m in dataTrackDB.mktDatas on s.mktcode equals m.mktcode
select new dataView {
Account=m.account,
brandcode=b.brandcode,
commodity=s.commodity,
date=s.date,
daysvalid=s.daysvalid,
mfrcode=b.mfrcode,
mktcode=s.mktcode,
price=s.price,
prodid=s.prodid,
statecode=s.statecode,
subcommodity=s.subcommodity,
supprecode=s.supprecode,
units =s.units
};
lstData = lstData.AsQueryable().Where(x => x.mfrcode == mfr );
return lstData.Take(100).ToList();
The problem is not in Linq but in your database
you can for example create a view that joins that way and the select the data in linq from the view
SELECT * FROM T1
INNER JOIN T2 ON
T1.Name COLLATE Latin1_General_CI_AS = T2.Name COLLATE Latin1_General_CI_AS
or select the data first in linq2sql separately for each table and then join it with linq2object
add COLLATE DATABASE_DEFAULT at the end of the query

Oracle all foreign key references

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;

Resources