Are nested parentheses in the FROM clause valid Oracle SQL syntax? - oracle

Does this query use correct Oracle syntax?
select * from ( ( ( dual a) ) ) where a.dummy = 'X';
It works in 11g and 12c but is it truly valid syntax? Or is this is just a compiler "mistake" that might be fixed in the future, causing the code the fail?
I doubt this is the correct syntax for the following reasons:
It doesn't seem to do anything other than add extra parentheses. Expressions like ((1+2)*3) can obviously benefit from nested parentheses but I don't see how they would ever help the FROM clause. And when I look at the above query the alias "a" looks out of scope.
I cannot find a valid path for this syntax in the SQL Language Reference syntax diagrams. On the other hand, it's easy to see how nested parentheses are permitted for expressions, conditions,
and subqueries. Expressions, conditions, and subqueries are recursive and can contain parentheses, but a join clause is not recursive.
I worry about this because there have been similar cases where invalid syntax worked in one release and then failed in the next. For example: select (select count(*) from (select * from scott.emp where ename = dual.dummy)) from dual;. That query worked in 10.2.0.1.0 but stopped working in later versions because table references are scoped to only one level deep.
The original query has a bad style but it's not worth changing our production queries unless there is a real problem with it.
Is the query invalid? Or is there some legitimate reason for that syntax, or is there some path in the syntax diagrams I'm missing?

It is legal syntax to use parenthesis in a join clause in a FROM, and the parentheses do have an effect.
Consider this query:
WITH table_a AS ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 30),
table_b as ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 20),
table_c AS ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 10)
SELECT a.id, b.id, c.id
FROM table_a a left join ( table_b b inner join table_c c ON c.id = b.id ) ON b.id = a.id
ORDER BY 1,2,3;
The parenthesis allow you to do an inner join of tables b and c and then outer join that to a.
Without the parenthesis, trying to express that as a left join would be impossible. You either wouldn't get rows 11-30 from table a or else rows 11-20 of table c would be nulls (depending on how you tried to do it).
Note that the above query is equivalent to:
WITH table_a AS ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 30),
table_b as ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 20),
table_c AS ( SELECT rownum id FROM DUAL CONNECT BY LEVEL <= 10)
SELECT a.id, b.id, c.id
FROM table_b b inner join table_c c on c.id = b.id right join table_a a on a.id = b.id
ORDER BY 1,2,3;
, which doesn't require parenthesis. So if you really want to avoid using parentheses in the FROM clause, you usually can do so. Personally, I prefer the LEFT JOIN method with parentheses instead of a RIGHT JOIN.

According to my reading of the syntax diagram for a SELECT statement, putting parentheses around a table reference in a SELECT statement is not allowed. As to whether or not Oracle might "fix" things in a way that would make this invalid, I have no way of knowing but I consider it unlikely. YMMV.
Best of luck.
EDIT
Just for fun I thought I'd put down my reading of the syntax diagram:
As other have noted, parentheses are allowed around a join_clause, but dual a is not a join_clause. Rather, it is a query_table_expression which is part of a table_reference. dual a cannot be a join_clause - to be such it would have to be followed by an inner_join_clause (e.g. INNER JOIN) or an outer_join_clause (e.g. LEFT OUTER JOIN, RIGHT OUTER JOIN or FULL OUTER JOIN), which it is not. Per the syntax diagram parentheses are not allowed around a query_table_expression unless the query_table_expression is preceded by ONLY, and in OP's query dual a is not preceded by ONLY. Thus I conclude that per the Oracle syntax diagrams ( ( (dual a) ) ) is not syntactically correct; however, the database seems to disagree. :-)

Additional to join_clause the subquery may be nested.
So this is perfect valid syntax
(((select * from dual)));
This provides the clue to the validity of the synax of the questioned query.
select * from (((dual)));
Starting with the select we go to query_block
select --> subquery --> query_block
query_block expands to
SELECT * FROM table_reference
From table_reference we step down to (nested) subquery, which can be further nested.
table_reference --> query_table_expression --> ( subquery )
So keep expanding subquery to get required nesting and finaly choose TABLE as the expansion of the query_table_expression
But as MT0 and others noted, this unfortunately don't lead to the e3xpected result. The maximal legal query is
select * from (((select * from dual)));

Related

Difference between standard outer left join and join using select

Is there any difference between these two statements:
-- Statement 1:
SELECT *
FROM Table1 t1
LEFT OUTER JOIN TABLE2 t2 on t1.id = t2.id
and
-- Statement 2:
SELECT *
FROM Table1 t1
LEFT OUTER JOIN (SELECT id, a, b, c FROM Table2) t2 on t1.id = t2.id
I'm not an expert but statement 2 just looks like poorly written sql, and like it would take much longer. I'm attempting to optimize a code block and it has many joins like the second one. Are they technically the same and I can just replace with the standard join statement 1?
Thanks!
Ps. This is Oracle, and working with 100's of millions of rows.
PSS. I'm doing my own detective work to figure out if they are the same, and time differences, was hoping an expert could explain if there is a technical difference what it is.
They are not same queries, with the lack of a criteria in the subquery that depends on whether the all columns and all column names of the TABLE2 is involved in the subquery. If the subquery involves all of the column names of the TABLE2 in the select list then they are the same query and the subquery is unnecessary. With subquery I refer to the part with a select statement after the join statement in the parens.
The first one uses the TABLE2 with its all columns, all those columns will be available in the result set where the criteria met.
However in the second one the table you make the JOIN is not the TABLE2 of yours but a table with just columns from TABLE2 specified in the subquery's SELECT list, namely id, a, b, and c. But it will have all the rows after this subquery since no criteria is enforced on it by a WHERE clause in the subquery.
You will have same number of rows with only selected columns participating from the TABLE2.
The second one is not necessarily the poorly written one. You could have a criteria to met before you JOIN to the TABLE2.

How to use Oracle hints or other optimization to fix function in where clause performance issue?

This is slow:
select col_x from table_a where col_y in (select col_y from table_b) and fn(col_x)=0;
But I know that this will return 4 rows fast, and that I can run fn() on 4 values fast.
So I do some testing, and I see that this is fast:
select fn(col_x) from table_a where col_y in (select col_y from table_b);
When using the fn() in the where clause, Oracle is running it on every row in table_a. How can I make it so Oracle first uses the col_y filter, and only runs the function on the matched rows?
For example, conceptually, I though this would work:
with taba as (
select fn(col_x) x from table_a where col_y in (select col_y from table_b)
)
select * from taba where x=0;
because I thought Oracle would run the with clause first, but Oracle is "optimizing" this query and making this run exactly the same as the first query above where fn(col_x)=0 is in the where clause.
I would like this to run just as a query and not in a pl/sql block. It seems like there should be a way to give oracle a hint, or do some other trick, but I can't figure it out. BTW, table is indexed on col_y and it is being used as an access predicate. Stats are up to date.
There are two ways you could go around it,
1) add 'AND rownum >=0' in the subquery to force materialization.
OR
2) use a Case statement inside the query to force the execution priority (maybe)
This works, but if anyone has a better answer, please share:
select col_x
from table_a
where col_y in (select col_y from table_b)
and (select 1 from dual where fn(col_x)=0);
Kind of kludgy, but works. Takes a query running in 60+ seconds down to .1 seconds.
You could try the HAVING clause in your query. This clause is not executed until the base query is completed, and then the HAVING clause is run on the resulting rows. It's typically used for analytic functions, but could be useful in your case.
select col_x
from table_a
where col_y in (select col_y from table_b)
having fn(col_x)=0;
A HAVING clause restricts the results of a GROUP BY in a
SelectExpression. The HAVING clause is applied to each group of the
grouped table, much as a WHERE clause is applied to a select list. If
there is no GROUP BY clause, the HAVING clause is applied to the
entire result as a single group. The SELECT clause cannot refer
directly to any column that does not have a GROUP BY clause. It can,
however, refer to constants, aggregates, and special registers.
http://docs.oracle.com/javadb/10.8.3.0/ref/rrefsqlj14854.html
1) Why you don't try join table_a and table_b using col_y.
select a.col_x from table_a a,table_b b
where a.col_y = b.col_y
and fn(col_x) = 0
2) NO_PUSH_PRED -
select /*+ NO_PUSH_PRED(v) */ col_x from (
select col_x from table_a where col_y in (select col_y from table_b)
) v
where fn(col_x) =0
3) Exists and PUSH_SUBQ.
select col_x from table_a a
where exists( select /*+ PUSH_SUBQ */ 1 from table_b b where a.col_y = b.coly )
and fn(col_x) = 0;

Oracle - EXCEPT Error

Have few columns and tables, as follows:
NOTE: The names of elements used are for illustrative purposes only.
SELECT T.col1
FROM Table1 T
WHERE NOT EXISTS (
(SELECT * FROM Table2)
EXCEPT (SELECT TT.col1
FROM TableTT TT
WHERE TT.col2 = T.col2)
);
Error: Missing right parenthesis, though the parentheses seem to match.
But, I do know that it has nothing to do with the parenthesis actually. And I suspect the error to be somewhere in the EXCEPT clause. What might have resulted in the error?
There's no EXCEPT operator in Oracle. Use MINUS instead. Reference: Here
In your query the word 'EXCEPT' is most probably treated as a table alias for (SELECT * FROM Table2) subquery.
UPDATE:
Full query for provided data structure will look like:
SELECT T.col1
FROM Table1 T
WHERE NOT EXISTS
((SELECT col1 FROM Table2)
MINUS
(SELECT TT.col1 FROM TableTT TT WHERE TT.col2 = T.col2));
Note that I have changed * to col1 for Table2 - if you're selecting single INT column TT.col1 from TT then you should also select single INT column from Table2.

Is an old Oracle syntax for outer joins (+) always equivalent to new syntax?

I wonder if it's always possible to rewrite LEFT JOIN using old Oracle syntax(+). In particular, I tried to express the following query using (+)
SELECT *
FROM table_1 a
LEFT JOIN table_2 b ON (b.table1_id = a.id AND b.other_field = 'value1')
without success. Is it possible at all?
Thank you.
I'm guessing you're not using the (+) operator in the test of b.other_field..
This should work:
SELECT *
FROM table_1 a, table_2 b
WHERE b.table1_id(+) = a.id
AND b.other_field(+) = 'value1'
If I recall correctly, it's not always possible to rewrite an ANSI join in Oracle's old outer join syntax, because the order of execution can change the rows returned.
What does "without success" mean? Did you get an error? Did you get the wrong rows? Did you get the wrong columns?
A left join will preserve all the rows in table_1. The basic form of old-style Oracle syntax is a Cartesian product with a WHERE clause, and a "+" token on the other table. (This doesn't include your entire WHERE clause. That's deliberate.)
SELECT *
FROM table_1 a, table_2 b
WHERE a.id = b.table1_id(+)
See, for example, AskTom.
For troubleshooting . . .
If you start with your query
SELECT *
FROM table_1 a
LEFT JOIN table_2 b ON (b.table1_id = a.id AND b.other_field = 'value1')
and eliminated the aliases, you'd have
SELECT *
FROM table_1
LEFT JOIN table_2 ON (table_2.table1_id = table_1.id AND
table_2.other_field = 'value1')
Are there actually columns named table_2.table1_id and table_1.id? Does that work?
If that's not the problem start simpler. Try this.
SELECT table_1.id, table_2.table1_id
FROM table_1
INNER JOIN table_2 ON (table_2.table1_id = table_1.id);
Does that work? Next try this.
SELECT table_1.id, table_2.table1_id
FROM table_1
LEFT JOIN table_2 ON (table_2.table1_id = table_1.id);
If that works, try adding the rest of your JOIN clause.

Using Table Cast

Can you use something on the line of
Select * from table(cast(select * from tab1 inner join tab2)) inner join tab3
Take into account that what's inside the table(cast()) is something much more complex than a simple select involving a block like with test as (select) select *... etc.
I need a simple way to do this preferably without the need for a temporary table.
Thank you.
Database: Oracle 10g
LE:
I have something like
Select a.dummy1, a.dummy2, wm_concat(t2.dummy3)
from table1 a,
(with str as
(Select '1,2,3,4' from dual)
Select a.dummy1, t.dummy3
from table1 a
inner join
(Select regexp_substr (str, '[^,]+', 1, rownum) split
from str
connect by level <= length (regexp_replace (str, '[^,]+')) + 1) t
on instr(a.dummy2, t.split) > 0) t2
where a.dummy1='xyz'
group by a.dummy1, a.dummy2
The main idea is that column t2.dummy3 contains CSVs. Thats why i have select '1,2,3,4' from dual.
I need to find all rows that contain at least one of the values from str.
Using any kind of loop is out of the question because further i need to integrate this into a larger query used for a report in SSRS, and the tables needed for this are quite large (>1mil rows)
CAST seem completely irrelevant here. You use CAST to change the perceived datatype of an expression. Here, you're passing it a result set, not an expression, and you're not saying what datatype to cast to.
You should be able to simply remove the TABLE and CAST calls and do something like:
SELECT * FROM (SELECT * FROM tab1 INNER JOIN tab2 ON ...) INNER JOIN tab3 ON ...
e.g.
SELECT * FROM
(SELECT d1.dummy FROM dual d1 INNER JOIN dual d2 ON d1.dummy=d2.dummy) d12
INNER JOIN dual d3 ON d12.dummy = d3.dummy
Subquery factoring should work fine here as well.
WITH x AS (SELECT * FROM DUAL)
SELECT * FROM
(SELECT d1.dummy FROM x d1 INNER JOIN x d2 ON d1.dummy=d2.dummy) d12
INNER JOIN dual d3 ON d12.dummy = d3.dummy;
If you're having difficulty getting that kind of construct to work, try adding more detail to your question about specifically what you've tried and what error you're getting.
Yeah... i found the answer... i was just too SQL n00b to see it as it was right in front of me...
i just took the "with" statement outside of the query and it worked.
thank you so much for your help, it was your answer that led me to see my mistake :D
Something like:
with str as
(Select '1,2,3,4' from dual)
Select a.dummy1, a.dummy2, wm_concat(t2.dummy3)
from table1 a,
(
Select a.dummy1, t.dummy3
from table1 a
inner join
(Select regexp_substr (str, '[^,]+', 1, rownum) split
from str
connect by level <= length (regexp_replace (str, '[^,]+')) + 1) t
on instr(a.dummy2, t.split) > 0) t2
where a.dummy1='xyz'
group by a.dummy1, a.dummy2

Resources