PL/SQL - Error when declaring a cursor with tables filled by other cursors - oracle

I have a problem when trying to create a cursor that uses tables filled after calling two other cursors, Oracle raised ORA-00942 exception - table or view does not exist. I tried to initialize the tables but it didnt change anything...
The idea was to recover buying prices(tsc.prxtar when tsc.achvte='A) and selling prices(tsc.prxtar when tsc.achvte='V') from a table, storing the results in two different tables and joining them at the end.
Does someone has any advice? Maybe an easier, more efficient way?
Thanks in advance!
DECLARE
CURSOR cursorA IS
SELECT pro.codpro as CodeProduit,
pro.nompro as NomProduit,
tsc.prxtar as PrixAchat
FROM pro
INNER JOIN tsc ON pro.codpro=tsc.codpro
WHERE tsc.achvte='A';
TYPE tableA IS TABLE OF cursorA%ROWTYPE;
tabA tableA:=tableA();
CURSOR cursorV IS
SELECT pro.codpro as CodeProduit,
pro.nompro as NomProduit,
tsc.prxtar as PrixVente
FROM pro
INNER JOIN tsc ON pro.codpro=tsc.codpro
WHERE tsc.achvte='V';
TYPE tableV IS TABLE OF cursorV%ROWTYPE;
tabV tableV:=tableV();
CURSOR cursorAV IS
SELECT tabA.CodeProduit,
tabA.NomProduit,
tabA.PrixAchat,
tabV.PrixVente
FROM tabA
INNER JOIN tabV ON tabA.CodeProduit=tabV.CodeProduit;
-- AND tabA.NomProduit=tabB.NomProduit;
TYPE tableAV IS TABLE OF cursorAV%ROWTYPE;
tableauDesPrix tableAV:=tableAV();
BEGIN
OPEN cursorA;
FETCH cursorA BULK COLLECT INTO tabA;
CLOSE cursorA;
OPEN cursorV;
FETCH cursorV BULK COLLECT INTO tabV;
CLOSE cursorV;
OPEN cursorAV;
FETCH cursorAV BULK COLLECT INTO tableauDesPrix;
CLOSE cursorAV;
END;

"Does someone has any advice? Maybe an easier, more efficient way?"
Why not write one SELECT statement which joins PRO to TSC twice?
SELECT pro.codpro as CodeProduit,
pro.nompro as NomProduit,
tsca.prxtar as PrixAchat,
tscv.prxtar as PrixVente
FROM pro
INNER JOIN tsc tsca ON pro.codpro = tsca.codpro
INNER JOIN tsc tscv ON pro.codpro = tscv.codpro
WHERE tsca.achvte = 'A'
AND tscv.achvte = 'V';
SQL is optimised for joins. It is more efficient to do everything in Plain Old SQL whenever possible. (There are edge cases where we might choose to do something in PL/SQL even though we could do it in SQL, but not here.)

You can not use the cursor name as a table name in the last cursor(cursorAV).
But I think you can achieve this using the single query as follows:
SELECT PRO.CODPRO AS CODEPRODUIT,
PRO.NOMPRO,
TSCA.PRXTAR AS PRIXACHAT,
TSCV.PRXTAR AS PRIXVENTE
FROM PRO
INNER JOIN TSCA
ON PRO.CODPRO = TSCA.CODPRO
INNER JOIN TSCV
ON PRO.CODPRO = TSCV.CODPRO
WHERE TSCA.ACHVTE = 'A'
AND TSCV.ACHVTE = 'V';

Related

SQL: ORA-00918 column ambiguously defined in INNER JOIN

I'm getting this error no matter what I do with the INNER JOIN Statement
Here is my code:
SELECT Package_Code, Description, Duration, Site_Code
FROM tbl_Holiday_Details
INNER JOIN tbl_Site_Visted
ON tbl_Holiday_Details.Package_Code = tbl_Site_Visted.Package_Code
INNER JOIN tbl_Site_Visted
ON tbl_Site_Details.Site_Code = tbl_Site_Visted.Site_Code
I don't understand what is the problem.
ps. if needed i will provide more code
The immediate problem is that at least Package_Code and Site_Code exist in multiple tables but your select does not specify which table you want to return data from. Yes, you know that you're doing an inner join on those columns so it doesn't matter which table's value is returned but the SQL syntax doesn't allow Oracle to make that inference. Generally, I would advise that you always alias every column both so it is clear which table a particular attribute is coming from and so that you don't break code when you add an attribute to a different table that happens to have the same name.
SELECT tbl_Holiday_Details.Package_Code,
Description,
Duration,
tbl_Site_Visted.Site_Code
FROM tbl_Holiday_Details
INNER JOIN tbl_Site_Visted
ON tbl_Holiday_Details.Package_Code = tbl_Site_Visted.Package_Code
INNER JOIN tbl_Site_Visted
ON tbl_Site_Details.Site_Code = tbl_Site_Visted.Site_Code
will work assuming Description and Duration are defined only in one of the three tables. I would add aliases to Description and Duration as well but I don't know which of the tables should be used. Of course, I would generally use simpler aliases (say, tsv for tbl_Site_Visited) rather than the full table name.
If you want to avoid aliasing your columns, you could use the USING clause rather than the ON clause
SELECT Package_Code,
Description,
Duration,
Site_Code
FROM tbl_Holiday_Details
INNER JOIN tbl_Site_Visted
USING( Package_Code )
INNER JOIN tbl_Site_Visted
USING( Site_Code )

Oracle join select result

I 've got this problem:
I have a select statement, which is rather time consuming.
I have to join the result with itself.
I want to do something like this:
Select table1.*, table2.Consumption
from (heavy select statement) table1 left outer join
(same heavy statement) table2
on table1."id" = table2."id" and table1."Year" -1 = table2."Year"
I don't want to catch the same data 2 times. I would rather like to do something like table1 table2. Is this possible?
I need this for an application, which executes querys but isn't able to use create or something like this, otherwise i would store the data in a table.
You can use a common table expression (CTE) and materialize the results of the heavy select statement:
WITH heavy AS ( SELECT /*+ MATERIALIZE */ ... (heavy select statemenet) )
Select table1.*, table2.Consumption
from heavy table1 left outer join
heavy table2
on table1."id" = table2."id" and table1."Year" -1 = table2."Year"

Join in Cursor query or two cursors, which is faster?

I need some suggestions for my cursor which is expected to run against millions of records. Here is my cursor query.
CURSOR items_cursor IS -- Brings only records that need to be updated
SELECT a.*, b.* FROM
( SELECT DataId, Name, VersionNum, OwnerId, SubType, LEVEL Lev FROM DTree
START WITH ParentId = startFrom CONNECT BY PRIOR DataId= ABS(ParentId) -- Brings ABS of ParentId
)a,
(
SELECT o.DataId pDataId, o.Permissions OwnerPerm, p.Permissions PublicPerm FROM DTreeAcl o, DTreeAcl p WHERE
o.DataId=p.Dataid AND o.AclType=1 AND p.AclType=3 AND (o.Permissions != ownerPerm OR p.Permissions != publicPerm)
)b
WHERE a.Lev >= 1 AND a.Lev <= 3 AND a.DataId = b.pDataId;
Is it better to get data from second table in another cursor inside the first cursor than join everything in first cursor itself??
A database is built to join. In the vast majority of cases, you're better off letting the database do the join in SQL rather than trying to write your own in PL/SQL.
The only way you'd be better off writing the join in PL/SQL would be if you know that you want a nested loop join and the Oracle optimizer chooses a much less efficient plan. In that case, though, you'd be better off getting the optimizer to give you the plan you want rather than writing a nested loop join in PL/SQL.

Order of columns in Oracle view is ignored

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,

Efficient Alternative to Outer Join

The RIGHT JOIN on this query causes a TABLE ACCESS FULL on lims.operator. A regular join runs quickly, but of course, the samples 'WHERE authorised_by IS NULL' do not show up.
Is there a more efficient alternative to a RIGHT JOIN in this case?
SELECT full_name
FROM (SELECT operator_id AS authorised_by, full_name
FROM lims.operator)
RIGHT JOIN (SELECT sample_id, authorised_by
FROM lims.sample
WHERE sample_template_id = 200)
USING (authorised_by)
NOTE: All columns shown (except full_name) are indexed and the primary key of some table.
Since you're doing an outer join, it could easily be that it actually is more efficient to do a full table scan rather than use the index.
If you are convinced the index should be used, force it with a hint:
SELECT /*+ INDEX (lims.operator operator_index_name)*/ ...
then see what happens...
No need to nest queries. Try this:
select s.full_name
from lims.operator o, lims.sample s
where o.operator_id = s.authorised_by(+)
and s.sample_template_id = 200
I didn't write sql for oracle since a while, but i would write the query like this:
SELECT lims.operator.full_name
FROM lims.operator
RIGHT JOIN lims.sample
on lims.operator.operator_id = lims.sample.authorized_by
and sample_template_id = 200
Does this still perform that bad?

Resources