Order of columns in Oracle view is ignored - oracle

I have a problem while creating views with a procedure, because the Oracle ignores the order of columns I specified.
I create the text of the command for creating view in a loop (in every loop one view), at the end of view I execute EXECUTE IMMEDIATE textOfCommand;
I tried to add /*+ORDERED */ before select but this did not help. (I also tried to run the queries directly, not from procedure)
The generated command itself is good, also column_id is good, but it is ignored in oracle developer or in geomedia. I think this will be something with optimization of the query, because there are several joins in the query.
I just cannot understand why it is so unpredictable, The order is sometimes good, sometimes not (if I run the same command several times) it doesn't depend on view, it is absolutely random, and I cannot figure out what is the reason.
If you have any idea, please share it. Thanks
EDIT :
I have a problem with the order of columns (not rows) that are shown in oracle developer and also geomedia. When I click the tab 'Columns' in Oracle developer, a can see all the columns of view with good COLUMN_ID, but they are not ordered by this column. I thought it was just the way, that the oracle developer displays it, but also other software has a problem with it. If I run the select command, the order is good. I wouldn't mind the order in oracle developer, but the problem is the customer's software (geomedia).
here is an examle of generated sql that is created by procedure and then run by EXECUTE IMMEDIATE command at the end of each loop in procedure. :
(there is something about 100 such a views. Tables, columns and orders is taken from one configuration table, that specifies all this. And I use GDOSYS.GPICKLISTS to identify FK and tables that should be joined)
CREATE OR REPLACE FORCE VIEW "SOME_VIEW" AS
SELECT /*+ORDERED */ a.ID AS "ID",
a8.TEXT_EN AS "COLUMN_NAME_1",
a.COLUMN_NAME_2 AS "COLUMN_NAME_2",
a.COLUMN_NAME_3 AS "COLUMN_NAME_3",
to_char(a.COLUMN_NAME_4,'yyyymmdd') AS "COLUMN_NAME_4",
to_char(a.COLUMN_NAME_5,'yyyymmdd') AS "COLUMN_NAME_5",
to_char(a.COLUMN_NAME_6,'yyyymmdd') AS "COLUMN_NAME_6",
to_char(a.COLUMN_NAME_7,'yyyymmdd') AS "COLUMN_NAME_7",
a.COLUMN_NAME_8 AS "COLUMN_NAME_8",
a.COLUMN_NAME_9 AS "COLUMN_NAME_9",
a.COLUMN_NAME_10 AS "COLUMN_NAME_10",
to_char(a.COLUMN_NAME_11,'yyyymmdd') AS "COLUMN_NAME_11",
a9.TEXT_EN AS "COLUMN_NAME_12",
a10.TEXT_EN AS "COLUMN_NAME_13",
a.COLUMN_NAME_14 AS "COLUMN_NAME_14",
a11.TEXT_EN AS "COLUMN_NAME_15",
FROM SOME_TABLE a
LEFT JOIN IENC.TABLE1 a8 on a8.id = a.COLUMN_NAME_1
LEFT JOIN IENC.TABLE2 a9 on a9.id = a.COLUMN_NAME_12
LEFT JOIN IENC.TABLE3 a10 on a10.id = a.COLUMN_NAME_13
LEFT JOIN IENC.TABLE4 a11 on a11.id = a.COLUMN_NAME_15

I assume what is "unpredictable" is something like
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW';
If you want to order rows by some column, you must explicitly add ORDER BY clause.
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW'
ORDER BY column_id;

Try without the double quote for the columns' name.
SELECT /*+ORDERED */ a.ID AS "ID", => SELECT /*+ORDERED */ a.ID AS ID,

Related

Oracle EF Database first is not completing

When I attempt to reverse engineer models off of an Oracle database, I am getting errors when the table in question has more than one trigger on the a column. I am putting a web UI on an upgraded Oracle 7 database (it has been migrated to Oracle 18C). The original system is an old Unix terminal UI. My solution is read only. Solution is .NET Core 3.1 and Oracle.EntityFrameworkCOre is 3.19.110.
When I run the above command on a table that has more than one trigger on a column, it errors.
Scaffold-DbContext "User Id=<user>; Password=<pwd>; Data Source=<datasource>;" Oracle.EntityFrameworkCore -OutputDir Models -Context GlobalContext
Using verbose mode I get the following.
Sequence contains more than one matching element
at System.Linq.ThrowHelper.ThrowMoreThanOneMatchException()
The generated SQL is
select u.*, v.trigger_name, v.table_name, v.column_name, v.table_owner
from (SELECT sys_context('userenv', 'current_schema') as schema, c.table_name, c.column_name, c.column_id, c.data_type, c.char_length, c.data_length, c.data_precision, c.data_scale, c.nullable, c.identity_column, c.data_default, c.virtual_column, c.hidden_column
FROM user_tab_cols c INNER JOIN (select distinct object_name as table_name from user_objects where object_type in ('TABLE', 'VIEW', 'MATERIALIZED VIEW')) t ON t.table_name=c.table_name WHERE t.table_name <> '__EFMigrationsHistory' AND (t.table_name IN (:t0) AND CONCAT(sys_context('userenv', 'current_schema'), CONCAT('.', t.table_name)) IN (:sdott0)) )u
left join USER_TRIGGER_COLS v on u.table_name = v.table_name and u.column_name = v.column_name and u.schema = v.table_owner
ORDER BY u.column_id
The results are as follows (I've made the table/triggers generic, but you see the issue)
Short of dropping the triggers, is there a way to reverse engineer the table?

Access union all into new table

I have a saved query (MyUnion) for a union, appending monthly files (linked views):
select * from RawTrade1801
union all
select * from RawTrade1802
Trying to write this to a new table is proving problematic:
SELECT MyUnion.* into RawTrade2
FROM MyUnion
WHERE Field8 = 'ZAR';
I get an error: Cannot open database "
My aim is to once a month create a master table by appending every monthly file.
The following steps should generate a table from your UNION query:
Create a new query. In the SQL View, now type:
SELECT * FROM (SELECT * FROM RawTrade1801
UNION ALL
SELECT * FROM RawTrade1802);
Save the query. In its Design View click the Make Table button. Type in the table name (e.g. NewTable) that you want the output of this query to be.
Save and close the query.
The query icon will have changed. Double click on it and it should generate your table.
Access actually changes the SQL to
SELECT * INTO NewTable FROM
(SELECT * FROM RawTrade1801
UNION ALL
SELECT * FROM RawTrade1802) AS [%$###_Alias];
when you view the SQL after step 4.
Try using INSERT INTO ... SELECT:
INSERT INTO RawTrade2
SELECT * FROM RawTrade1801 WHERE Field8 = 'ZAR'
UNION ALL
SELECT * FROM RawTrade1802 WHERE Field8 = 'ZAR';
Of course, even if this works it still does not explain why your original query does not work. I expect it is a slight technical problem, though I don't know enough Access to see it immediately.
Create the Union query, save it with the name like 'qUnion'.
From menu open:
Create-->Query--> Make Table.
In Add Table Menu chose "Queries" and
Add your union query ('qUnion').
Select the fields that you need.
Open query.
Anew table will be created.

Oracle ignores hint for index with synonym and 2 views

This is the query i am running:
select /*+ index(V_AMV_PLG_ORDER_HISTORY_200_MS.orders.T0 IDX_ORDER_VERSION_3) */ *
from V_AMV_PLG_ORDER_HISTORY_200_MS
where EXCHANGE_SK = 32 and PRODUCT_SK = 1000169
And it uses a different index than the one i am ordering it to.
As you can see, I am querying from the view V_AMV_PLG_ORDER_HISTORY_200_MS, you can see its sql query here:
V_AMV_PLG_ORDER_HISTORY_200_MS view SQL Query:
SELECT AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME) AS ORDER_DATE_TIME,
SUM(orders.BASE_VOLUME) AS VOLUME,
SUM(orders.BASE_CURR_LIMIT_PRICE*orders.BASE_VOLUME)/SUM(orders.BASE_VOLUME) AS PRICE,
orders.PRODUCT_SK AS PRODUCT_SK,
orders.EXCHANGE_SK AS EXCHANGE_SK,
orders.DIRECTION_CD AS DIRECTION_CD,
orders.AGG_UNIT_CD AS AGG_UNIT_CD,
orders.TRADER_KEY AS EXECUTING_REPRESENTATIVE_KEY,
orders.ACCOUNT_KEY AS ACCOUNT_KEY,
a.BUSINESS_UNIT_CD AS BUSINESS_UNIT_CD
FROM AMV_PERF_PROFILES_FRONTEND.S_AMV_ORDER_VERSION_NEW orders
INNER JOIN AMV_PERF_PROFILES_FRONTEND.S_AMV_ACCOUNT a
ON a.ACCOUNT_KEY = orders.ACCOUNT_KEY
WHERE BASE_VOLUME > 0
GROUP BY AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME),
orders.PRODUCT_SK,
orders.EXCHANGE_SK,
orders.ACCOUNT_KEY,
a.BUSINESS_UNIT_CD,
orders.AGG_UNIT_CD,
orders.TRADER_KEY,
orders.DIRECTION_CD;
He is getting the data using the Synonym S_AMV_ORDER_VERSION_NEW, Which directs to another Scheme, to a view called V_AMV_ORDER_VERSION and refering to it as orders, its sql query here:
V_AMV_ORDER_VERSION view Sql query:
SELECT T1.ENTITY_KEY ,
T2.AGG_UNIT_CD ,
T0.BASE_CURR_LIMIT_PRICE ,
T7.DIRECTION_CD ,
T0.EXCHANGE_SK,
T0.ORDER_LOCAL_DATE_TIME ,
T0.PRODUCT_SK,
T18.ENTITY_KEY ,
T19.ENTITY_KEY ,
T0.NOTIONAL_VALUE2 ,
T0.NOTIONAL_VALUE ,
T0.ORDER_GLOBAL_DATE_TIME ,
T0.BASE_VOLUME ,
T31.TRANSACTION_STATUS_CD ,
T0.ORDER_VERSION_KEY
FROM ETS_UDM_CDS_NEW.ORDER_VERSION T0
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T1
ON T0.ACCOUNT_SK = T1.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.AGG_UNIT T2
ON T0.AGG_UNIT_SK = T2.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.DIRECTION T7
ON T0.DIRECTION_SK = T7.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T18
ON T0.LOCAL_TIME_ZONE_SK = T18.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.ENTITY T19
ON T0.TRADER_SK = T19.ENTITY_SK
LEFT OUTER JOIN ETS_UDM_CDS_NEW.TRANSACTION_STATUS T31
ON T0.TRANSACTION_STATUS_SK = T31.ENTITY_SK;
Which takes its data from a table called ORDER_VERSION and refers to it as T0
this table has an index called IDX_ORDER_VERSION
The problem is that oracle ignores my hint, And uses a different index, Now, I have managed to use a hint to make oracle use an index i wanted when i was querying a view that gets data from a table, But this time I am querying a view which gets his data from another view which gets his data from a table.
And also, The second view in the line is on a different Scheme and i am using a synonym, So perhaps that is why i am missing something Cuz i tried many combinations of possible solutions i found on google but nothing seems to be working...
I would say that if i go one step forward and query directly from V_AMV_ORDER_VERSION (Without the synonym) IT works and i can make oracle work with any index i want, so this query works perfect:
select /*+ index(orders.T0 IDX_ORDER_VERSION_5) */ * from V_AMV_ORDER_VERSION orders
where EXCHANGE_SK =32 and PRODUCT_SK = 1000169
Well me and our company's DBA looked at it for a while, it seems like an Oracle bug in the Global Hint manifestation, We have created the view V_AMV_PLG_ORDER_HISTORY_200_MS using a regular join rather than an ANSI join, and now it works properly:
V_AMV_PLG_ORDER_HISTORY_200_MS view SQL Query:
SELECT AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME) AS ORDER_DATE_TIME,
SUM(orders.BASE_VOLUME) AS VOLUME,
SUM(orders.BASE_CURR_LIMIT_PRICE*orders.BASE_VOLUME)/SUM(orders.BASE_VOLUME) AS PRICE,
orders.PRODUCT_SK AS PRODUCT_SK,
orders.EXCHANGE_SK AS EXCHANGE_SK,
orders.DIRECTION_CD AS DIRECTION_CD,
orders.AGG_UNIT_CD AS AGG_UNIT_CD,
orders.TRADER_KEY AS EXECUTING_REPRESENTATIVE_KEY,
orders.ACCOUNT_KEY AS ACCOUNT_KEY,
a.BUSINESS_UNIT_CD AS BUSINESS_UNIT_CD
FROM AMV_PERF_PROFILES_FRONTEND.S_AMV_ORDER_VERSION_NEW orders,
AMV_PERF_PROFILES_FRONTEND.S_AMV_ACCOUNT a
WHERE BASE_VOLUME > 0 AND a.ACCOUNT_KEY = orders.ACCOUNT_KEY
GROUP BY AMV_PERF_PROFILES_FRONTEND.AMV_PLG_GET_SEGMENT(200, orders.ORDER_GLOBAL_DATE_TIME),
orders.PRODUCT_SK,
orders.EXCHANGE_SK,
orders.ACCOUNT_KEY,
a.BUSINESS_UNIT_CD,
orders.AGG_UNIT_CD,
orders.TRADER_KEY,
orders.DIRECTION_CD;

Finding sequences and triggers associated with an Oracle table

I have used this query to fetch the list of sequences belonging to an Oracle database user:
SELECT * FROM all_sequences x,all_tables B
WHERE x.sequence_owner=B.owner AND B.TABLE_NAME='my_table';
But that database user is having many more sequence also, so the query returns me all the sequence of the database user. Can anybody help me to find the particular sequence of my_table using query so that I can get the auto increment id in my application.
i want the query which fetch list of table of my database user with the sequence and triggers used in the table
You can get the triggers associated with your tables from the user_triggers view. You can then look for any dependencies recorded for those triggers in user_dependencies, which may include objects other than sequences (packages etc.), so joining those dependencies to the user_sequences view will only show you the ones you are interested in.
Something like this, assuming you are looking at your own schema, and you're only interesting in triggers that references sequences (which aren't necessarily doing 'auto increment', but are likely to be):
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from user_tables tabs
join user_triggers trigs
on trigs.table_name = tabs.table_name
join user_dependencies deps
on deps.name = trigs.trigger_name
join user_sequences seqs
on seqs.sequence_name = deps.referenced_name;
SQL Fiddle demo.
If you're actually looking at a different schema then you'll need to use all_tables etc. and filter and join on the owner column for the user you're looking for. And if you want to include tables which don't have triggers, or triggers which don't refer to sequences, you can use outer joins.
Version looking for a different schema, though this assumes you have the privs necessary to access the data dictionary information - that the tables etc. are visible to you, which they may not be:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from all_tables tabs
join all_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join all_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join all_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
If that can't see them then you might need to look at the DBA views, again if you have sufficient privs:
select tabs.table_name,
trigs.trigger_name,
seqs.sequence_name
from dba_tables tabs
join dba_triggers trigs
on trigs.table_owner = tabs.owner
and trigs.table_name = tabs.table_name
join dba_dependencies deps
on deps.owner = trigs.owner
and deps.name = trigs.trigger_name
join dba_sequences seqs
on seqs.sequence_owner = deps.referenced_owner
and seqs.sequence_name = deps.referenced_name
where tabs.owner = '<owner>';
One way would be to run these queries to check if there are any sequence's Pseudocolumns (NEXTVAL and CURRVAL ) used in your functions , procedures, packages, Triggers or PL/SQL JAVA SOURCE.
select * from user_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
select * from all_source where
UPPER(TEXT) LIKE '%NEXTVAL%';
Then go to the specific Procedure, Function or Trigger to check which column/table gets populated by a sequence.
The query could also be used with '%CURRVAL%'
This might not help if you are running inserts from JDBC or other external applications using a sequence.
Oracle 12c introduced the IDENTITY columns, using which you could create a table with an identity column, which is generated by default.
CREATE TABLE t1 (c1 NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
c2 VARCHAR2(10));
This will internally create a sequence that auto-generates the value for the table's column.So, If you would like to know which sequence generates the value for which table, you may query the all_tab_columns
SELECT data_default AS sequence_val
,table_name
,column_name
FROM all_tab_columns
WHERE OWNER = 'HR'
AND identity_column = 'YES';
SEQUENCE_VAL |TABLE_NAME |COLUMN_NAME
-----------------------------------------|-------------------------------------
"HR"."ISEQ$$_78160".nextval |T1 |C1
I found a solution to this problem to guess the sequence of a particular sequence
select * from SYS.ALL_SEQUENCES where SEQUENCE_OWNER='OWNER_NAME' and LAST_NUMBER between (select max(FIELD_NAME) from TABLE_NAME) and (select max(FIELD_NAME)+40 from TABLE_NAME);
This query will guess by search the LAST_NUMBER of the sequence value between MAX value of the field using sequence and Max value + 40 (in my case cache value is 20, so I put 40)
select SEQUENCE_NAME from sys.ALL_TAB_IDENTITY_COLS where owner = 'SCHEMA_NAME' and table_name = 'TABLE_NAME';

Order of columns returned in SQL query (With table join)

I am wondering what determines the order of columns returned in a SQL query.
For example, SELECT * FROM SOMETABLE;
SQ_ID |BUS_TYPE |VOIP |LOCAL_PHONE
--------|-----------|---------|-------------
SQ000001|Business |Y |N
I am guessing the attribute COLUMN_ID determines this. In the case of a table join, for example, SELECT * FROM SOMETABLE LEFT JOIN OTHERTABLE USING (SOME_COL); how is the order now determine.
The order of columns in SELECT * FROM some_table is determined by the column_id of each column, as seen in USER_TAB_COLUMNS.
The order of columns in SELECT * FROM some_table JOIN other_table is all the columns for each table starting with the leftmost table after the FROM clause. In other words, this ...
SELECT * FROM some_table JOIN other_table
... is equivalent to this ...
SELECT some_table.*, other_table.* FROM some_table JOIN other_table
Changing that inner join to LEFT JOIN or RIGHT JOIN won't change the projection.
This is, of course, theoretical. We should never use select * in production code. Explicit column declarations, with table aliases when joining, are always safer. Apart from better expression of intent, explicit projections protect our code from future changes to the tables such as adding a LOB column or a column name which creates ambiguity with a joined table's column.
You can list the order of the colums in the Select statement:
SELECT SOME_COL, SOME_OTHER_COL
FROM SOMETABLE LEFT JOIN OTHERTABLE USING (SOME_COL)
But you also speak of the ID influencing the order and of ordering in general. So I think you could also be looking for ORDER BY to order the rows:
SELECT *
FROM SOMETABLE LEFT JOIN OTHERTABLE USING (SOME_COL)
ORDER BY SOME_COL
What also comes quite handy in this case is the use of aliases. Especally when both tables have coloums with the same name:
SELECT s.some_col, o.some_col
FROM SOMETABLE s LEFT JOIN OTHERTABLE o ON(o.id = s.id)
ORDER BY o.SOME_COL
I use the ON JOIN syntax in this case, because i find this more intuive when using aliases but it should also work with USING.

Resources