Recursive records oracle - oracle

I'm currently trying to create a report using SQL Developer.
I have these 2 tables:
PERSONS (IDPerson, NamePerson)
PENALTIES (IDPenalty, DatePenalty, Description, IDPerson)
The tables are polulated.
How could I create a table like
using recursive queries in SQL? or it's there any other solution?
Thank you in advance.

select p.nameperson as name, p.idperson as id,
listagg(to_date(x.datepenalty, 'dd/mm/yyyy') || ' - ' || x.description, '; ')
within group (order by x.datepenalty) as penalties
from persons p left outer join penalties x
on p.idperson = x.idperson
group by p.idperson;
(Not tested - you didn't provide test data.)

Related

How to determine if an Index is required for my Oracle query

i would like to know if an index is required or would help to run the below query? i dont have any idea how can i analyze this question.
if some one can help please thanks
WITH C(A0_ID, A1_ID, A1_Col0)
AS (
SELECT
Table_1.ID AS A0_ID,
Table_2.ID AS A1_ID,
Table_2.Col0 AS A1_Col0
FROM Table_1 ,Table_2
WHERE Table_2.ID = Table_1.ID
AND Table_1.col1 = ?
AND BITAND(Table_1.col2, ?) <> ?
AND Table_2.col3 IN (?,?,?)
), T(A0_ID, A1_ID, A1_Col0) AS (
SELECT
A0_ID,
A1_ID,
A1_Col0
FROM C
WHERE A1_ID = ?
UNION ALL
SELECT
C.A0_ID,
C.A1_ID,
C.A1_Col0
from C
INNER JOIN T P ON C.A1_Col0 = P.A1_ID
) SELECT A0_ID, A1_ID, A1_Col0 FROM T
The main query selects from T with no post-processing (filtering, aggregation, sorting, etc.), so it doesn't require optimization.
T is a recursive CTE based on the subquery C. Therefore, T doesn't need optimization (unless you materialized it, but that's a different story).
Now, C can be optimized:
I would consider Table_1 as the driving table since it has an equality in the filtering criteria. It also, uses ID to join against Table_2. Therefore a good index for it is:
create index ix1 on Table_1 (col1, ID);
Then, to access Table_2 you'll need to get through ID that should be the main index column. You may add col3 to the index to somewhat improve the performance of the query; only a benchmark will tell if this is a wise idea. The index could look like:
create index ix2 on Table_2 (ID, col3); -- col3 is optional here
I would recommend you create these indexes and compare the performance that each option produces.

ORA-00907 Missing Right Parenthesis (Oracle)

I was previously holding my data in SharePoint. At that time, the below query ran fine :-
SELECT Nz(Abs(Sum(sales_route="Sales Mailbox")),0) AS AcceptDirect
FROM tblQuotesNew AS t1;
Now that I have moved my data to Oracle (but still retrieving it via Access), I get the error ORA-00907 Missing Right Parenthesis.
Can anyone suggest how I can modify the code above that that it is acceptable to Oracle?
Thanks in advance
I think your query counts number of rows with sales_route as 'Sales Mailbox' which can be simply written as:
select count(*) as AcceptDirect
from tblQuotesNew
where sales_route = 'Sales Mailbox';
If you want counts for different routes in the same query, you can do something like this:
select count(case when sales_route = 'Sales Mailbox' then 1 end) as AcceptDirect,
count(case when sales_route = 'XYZ' then 1 end) as XYZ
from tblQuotesNew
where sales_route in ('Sales Mailbox', 'XYZ');

Oracle APEX select values into classic report rows

I'm working on an Oracle database-driven web app using apex.There is a P2_ROWS field which contains a list of values selected from the data table, defined in the source sql query. There is a button on the report region, which allows users to sort the list of values in a certain order. A dynamic action is assigned to the button. When the button is clicked, a PL/SQL is executed with a order by query that should change the order in which the rows are displayed.
The source sql is defined as:
select
"PRODUCT_ID",
"PRODUCT_NAME",
"PRODUCT_DESCRIPTION",
"PRICE",
"PRODUCT_LOCATION",
dbms_lob.getlength("THUMBNAIL") as "THUMBNAIL"
from "PRODUCTS"
where
(
instr(upper("PRODUCT_NAME"), upper(nvl(:P2_REPORT_SEARCH, "PRODUCT_NAME"))) > 0
)
The PL/SQL assigned to the button is:
SELECT PRODUCTS.PRODUCT_ID, PRODUCTS.PRODUCT_NAME, PRODUCTS.PRODUCT_DESCRIPTION, PRODUCTS.PRICE, PRODUCTS.PRODUCT_LOCATION, dbms_lob.getlength("THUMBNAIL") as "THUMBNAIL"
INTO :P2_ROWS
FROM PRODUCTS
INNER JOIN TEMP_DISTANCES ON TEMP_DISTANCES.PRODUCT_ID = PRODUCTS.PRODUCT_ID
ORDER BY DISTANCE ASC;
When the button is clicked, the app returns error " ORA-00947: not enough values ORA-06550".
How would you solve this? Please feel free to comment and feel free to suggest any improvement ideas. Thanks.
As #Scott say you trying select many values into one scalar variable. You should define few variables or use concatenation.
SELECT PRODUCTS.PRODUCT_ID, PRODUCTS.PRODUCT_NAME, PRODUCTS.PRODUCT_DESCRIPTION, PRODUCTS.PRICE, PRODUCTS.PRODUCT_LOCATION, dbms_lob.getlength("THUMBNAIL") as "THUMBNAIL"
INTO :P2_PROID_ID, :P2_PROD_NAME, ...
FROM PRODUCTS
INNER JOIN TEMP_DISTANCES
ON TEMP_DISTANCES.PRODUCT_ID = PRODUCTS.PRODUCT_ID
ORDER BY DISTANCE ASC;
or
SELECT PRODUCTS.PRODUCT_ID || ', ' || PRODUCTS.PRODUCT_NAME || ', ' || PRODUCTS.PRODUCT_DESCRIPTION || ', ' || PRODUCTS.PRICE ...
INTO :P2_ROWS
FROM PRODUCTS
INNER JOIN TEMP_DISTANCES
ON TEMP_DISTANCES.PRODUCT_ID = PRODUCTS.PRODUCT_ID
ORDER BY DISTANCE ASC;

Optimize multiple subselects with WITH clause in Oracle

I have a query like:
select
qsn.code,
(select prs.display_name from prs where prs.id = qsn.fk_prs) display_name,
(select prs.address from prs where prs.id = qsn.fk_prs) address,
(select prs.tel from prs where prs.id = qsn.fk_prs) tel
from
qsn
where
qsn.register_date between :x1 and :x2
When I look at the execution plan of the query, it queries prs table 3 times (each time using INDEX UNIQUE SCAN).
I wonder if I can query the prs table once using WITH clause? How can I write the query that way.
I shall mention that because each of the tables have millions of record, joining them makes the query so slow.
using with clause your query goes like this:
with abc as (select id,
display_name ,
address ,
tel
from prs)
select
qsn.code,
abc.display_name,
abc.address,
abc.tel
from qsn
inner join abc
on qsn.fk_prs = abc.id
where qsn.register_date between :x1 and :x2 ;
ps: not tested.
Use a join:
select qsn.code, prs.display_name, prs.address, prs.tel
from qsn
left join prs on prs.id = qsn.fk_prs
where qsn.register_date between :x1 and :x2

prevent full table scan

I have following query:
select id,
c1,
c2,
c3
from tbl t1
join
(select id
from tbl t2
where upper(replace(c5, ' ', '')) like upper(?)
) j
on j.id = t1.id
? is some wildcard parameter string like %test%.
c5 column has index on the function used to access it:
create index tbl_c5_idx on tbl(upper(replace(c5, ' ', '')))
When I run just inner query it uses tbl_c5_idx, however when I run the whole query it turns into full table scan which is much slower.
Are there any way to avoid full table scans? Hints or rewrite join condition. I can not rewrite whole query as inner query is constructed dynamically depending on the input conditions.
A very basic example to test your functionality
create table test(id number,value varchar2(200));
insert into test values(1,'gaurav is bad guy');
insert into test values(2,'gaurav is good guy');
SELECT *
FROM test
WHERE UPPER (REPLACE (VALUE, ' ', '')) LIKE UPPER ('%gauravisbad%');
before creating index this is doing a full table scan for obvious reason ,because no index get created.
create index tbl_c5_idx on test(upper(replace(value, ' ', '')));
The reason why i am asking you to avoid inner join on the same table because you're using the table twice once to get your records from your filter condition where your index are used and then join on the basis of id which is preventing of using index ,because you dont have index on id column,this can be done with a simple filter condition.
Please let me know if you're again finding out the same issue of full table scan ,or you're not getting the same result from this query .
if you're running the subquery only, it doesn't use the id column in the filters the way the parent query does, therefore the index can be used. In the parent query you are using the id as well, which prevents the index from being used. Maybe adding an index on (id, upper(replace(c5, ' ', ''))) would solve the problem.
Gaurav Soni is right: you don't need a subquery to achieve your goal.
always check performances rather than the explain plan. Performances might just be worst with your hint than without. Oracle is NOT stupid.
Seems I found solution, or at least a thing that helps.
I used index hint, so access is done with tbl_c5_idx.
That is how final query looks now:
select /*+ index(t1) */ id,
c1,
c2,
c3
from tbl t1
join
(select id
from tbl t2
where upper(replace(c5, ' ', '')) like upper(?)
) j
on j.id = t1.id

Resources