Oracle subquery does not see the variable from the outer block 2 levels up
No, Oracle
doesn't correlate the subqueries nested more than one level deep (and neither does MySQL
).
This is a well-known problem.
Use this:
SELECT p.post_id, c.*
FROM posts
JOIN (
SELECT c.*, ROW_NUMBER() OVER (PARTITION BY post_id ORDER BY created_date ASC) AS rn
FROM comments c
) c
ON c.post_id = p.post_id
AND rn = 1
Oracle subquery in select
Your problem is that you can't use your aliased columns deeper than one sub-query. According to the comments, this was changed in 12C, but I haven't had a chance to try it as the data warehouse that I use is still on 11g.
I would use something like this:
SELECT b.cod_aux AS product
,ROUND (r.valorultent, 2) AS valorultent
FROM pchistest a
JOIN pcembalagem b ON (a.codprod = b.codprod)
JOIN (SELECT valorultent
,codprod
,ROW_NUMBER() OVER (PARTITION BY codprod
ORDER BY dtultent DESC)
AS row_no
FROM pchistest) r ON (r.row_no = 1 AND r.codprod = b.codprod)
GROUP BY a.codprod, b.cod_aux
ORDER BY b.cod_aux
I avoid sub-queries in SELECT statements. Most of the time, the optimizer wants to run a SELECT for each item in the cursor, OR it does some crazy nested loops. If you do it as a sub-query in the JOIN, Oracle will normally process the rows that you are joining; normally, it is more efficient. Finally, complete your per item functions (in this case, the ROUND) in the final product. This will prevent Oracle from doing it on ALL rows, not just the ones you use. It should do it correctly, but it can get confused on complex queries.
The ROW_NUMBER() OVER (PARTITION BY ..) is where the magic happens. This adds a row number to each group of CODPRODs. This allows you to pluck the top row from each CODPROD, so this allows you to get the newest/oldest/greatest/least/etc from your sub-query. It is also great for filtering duplicates.
Subquery that accesses main table fields combined with LIMIT clause in Oracle SQL
Please try with analytic function:
with tp as (select t.*, row_number() over (partition by taskListCode order by importance desc) r
from tasks t
where isReady = 1 /*or 'Y' or what is positive value here*/)
select u.name, tp.description
from users u left outer join tp on (u.taskListCode = tp.taskListCode)
where tp.r = 1;
Subquery function invoked twice if alias is used in main SQL
The SQL engine is opting to not materialize the subquery and is pushing the function calls into the outer query where it gets called multiple times for each row. You need to force the function to be evaluated in the subquery where it is called rather than allowing the SQL engine to rewrite the query.
One method is use ROWNUM
to force it to materialize the inner query:
SELECT A1 + A1
FROM (SELECT FCN_SLOW () AS A1
FROM DUAL
WHERE ROWNUM >= 1)
Another method is to use a CTE
with the (undocumented) materialize
hint:
WITH slow_query(a1) AS (
SELECT /*+ materialize */
FCN_SLOW ()
FROM DUAL
)
SELECT A1 + A1
FROM slow_query
db<>fiddle here [which takes 20 seconds to run... not 30 seconds.]
You can see a similar example with materializing sequence values (rather than sleeping) in this answer.
Fetch subquery value from cursor to parameter in PL/SQL
The columns of sub queries are not projected so you can't reference them. If you want the CUSTOMER_ID
and NEW_REFERENCE_ID
in your program you will have to select them in the top level SELECT
clause.
The easiest answer to your solution is to just open a cursor for your
subquery itself, for eample:
BEGIN
FOR cur IN (SELECT crs_cust.CUSTOMER_ID, subset.NEW_REFERENCE_ID
FROM CRS_CUSTOMERS crs_cust
INNER JOIN DAY0_SUBSET subset ON
crs_cust.CUSTOMER_ID=subset.CURRENT_CUSTOMER_ID)
LOOP
DBMS_OUTPUT.PUT_LINE(cur.customer_id || ', ' || cur.new_reference_id);
END LOOP;
END;
/
PLSQL - IN clause using variable with multiple values
Declare the type globally:
CREATE TYPE number_list IS TABLE OF NUMBER;
Then you can initialise the list and then, in each iteration of the loop, EXTEND
the list and assign the value and, finally, use the MEMBER OF
operator or IN
with a subquery and table collection expression:
DECLARE
l_id_list NUMBER_LIST := NUMBER_LIST();
BEGIN
FOR i IN 1..l_row_count
LOOP
l_id_list.EXTEND;
l_id_list(l_id_list.COUNT) := to_number(
apex_json.get_varchar2(
p_path => 'rows[%d].id',
p0 => i,
p_values => l_values
)
);
END LOOP;
SELECT *
-- BULK COLLECT INTO ...
FROM mytable
WHERE someid MEMBER OF l_id_list;
-- or
SELECT *
-- BULK COLLECT INTO ...
FROM mytable
WHERE someid IN (SELECT COLUMN_VALUE FROM TABLE(l_id_list));
END;
Related Topics
Rails Order by Association Field
Does "Select for Update" Prevent Other Connections Inserting When the Row Is Not Present
Copy Data from One Existing Row to Another Existing Row in SQL
Why Can't I Create a View Inside of a Begin ... End Block
Ora-06502: Pl/Sql: Numeric or Value Error: Character String Buffer Too Small
How to Get Column Names from a Query in SQL Server
Get the List of Stored Procedures Created And/Or Modified on a Particular Date
Ms Access - Execute a Saved Query by Name in Vba
Solution for Speeding Up a Slow Select Distinct Query in Postgres
How to Check for The SQL Server Version Using Powershell
Postgres: Select All Row with Count of a Field Greater Than 1
Query Temp Table in Stored Proc Whilst Debugging in SQL 2008 Management Studio
Sql Parentheses Use in an or Clause
Mod' Is Not a Recognized Built-In Function Name
How to Use a Case Statement in Scalar Valued Function in Sql