Referencing outer query's tables in a subquery
i think that won't work, because you're referencing your derived table 'c' as part of a join.
however, you could just take out the WHERE p.user = u.id
though and replace with a GROUP BY p.user
in the derived table, because the ON c.user = u.id
will have the same effect.
Why am I able to reference an outer queries columns from within a subquery?
When you have multiple tables in a query, always use qualified table names. You think the query is doing:
SELECT t1.col_a
FROM test_1 t1
WHERE t1.col_a IN (SELECT t2.col_a FROM test_2 t2);
This would generate an error, because t2.col_a
does not exist.
However, the scoping rules for subqueries say that if the column is not in the subquery, look in the outer query. So, if t2.col_a
does not exist, then the query turns into:
SELECT t1.col_a
FROM test_1 t1
WHERE t1.col_a IN (SELECT t1.col_a FROM test_2 t2);
The solution is to qualify all column references so there is no ambiguity.
Join on TOP 1 from subquery while referencing outer tables
If that is the logic you want, you can use OUTER APPLY
:
SELECT C.ContactSys, GL.ABC, GL.XYZ,
... a bunch of other columns ...
FROM Users U JOIN
Contacts C
ON U.ContactSys = C.ContactSys LEFT JOIN
UserWatchList UW
ON U.UserSys = UW.UserSys LEFT JOIN
Accounts A
ON C.AccountSys = A.AccountSys OUTER APPLY
(SELECT TOP 1 gl.*
FROM GuestLog gl
WHERE gl.ContactSys = C.ContactSys
ORDER BY gl.GuestLogSys DESC
) GL
WHERE C.OrganizationSys = 1012 AND
U.UserTypeSys = 2 AND
C.FirstName = 'steve'
Referencing outer query in subquery
You can do something like this with a join:
select * from table a
inner join (
select id,
max(
if(`date` <= __LOWERLIMIT__ ,`date`, 0)
) as min_date,
min(
if(`date` >= __UPPERLIMIT__ , `date`, UNIX_TIMESTAMP())
) as max_date
from table
where id = __ID__
group by id
) range on
range.id = a.id and
a.`date` between min_date and max_date;
I'm not a MySQL expert, so apologies if a bit of syntax tweaking is needed.
Update: the OP also found this very nice solution.
PostgreSQL Referencing Outer Query in Subquery
Instead of joining an inline view based on the prices
table, you can perform a subquery in the SELECT list:
SELECT customer_id, quantity, (
SELECT price
FROM prices p
WHERE
p.customer_id = o.customer_id
AND p.effective_time <= o.timestamp
ORDER BY p.effective_time DESC
LIMIT 1
) AS price
FROM orders o
That does rely on a correlated subquery, which could be bad for performance, but with the way your data are structured I doubt there's a substantially better alternative.
mysql sub query reference outer table
This is your query, with table aliases making it a bit more readable:
SELECT SUM(trans_current_quantity) as quantity
FROM phppos_items i LEFT JOIN
phppos_location_items li
ON li.item_id = i.item_id and li.location_id IN (1) LEFT JOIN
(SELECT *
FROM phppos_inventory inv
WHERE inv.trans_date < '2018-05-06 23:59:59' and
trans_items = *XXX*
ORDER BY trans_date DESC LIMIT 1
) inv
ON li.item_id = inv.trans_items;
I can only interpret trans_current_quantity
as coming from phppos_inventory
. The LEFT JOIN
s appear to be superfluous as you've written the query.
What you really want is a lateral join. That doesn't work in MySQL, alas. Here is the next closest thing:
SELECT SUM(inv.trans_current_quantity) as quantity
FROM phppos_items i JOIN
phppos_location_items li
ON li.item_id = i.item_id and li.location_id IN (1) JOIN
phppos_inventory inv
ON li.item_id = inv.trans_items
WHERE li.item_id = XXX AND
inv.trans_date = (SELECT MAX(inv2.trans_date)
FROM phppos_inventory inv2
WHERE inv2.trans_date < '2018-05-07' and
inv2.trans_items = li.item_id
);
I also fixed the date comparison by adding a second. If that's not right, you can fix it, but the query is more readable.
Best way to reference an outer query / subquery?
So, as one commenter pointed out, I think you would do much better off using JOINS, than sub-selects. For example, if I am reading your query/problem correctly, you could do a join query like this:
SELECT t1.name, t1.email, t3.job_id
FROM table_users t1
LEFT JOIN table_users_job t2
ON t1.user_id = t2.user_id
LEFT JOIN table_jobs t3
ON t3.job_id = t2.job_id
WHERE t2.period = 'night
AND t3.status = 'available_position'
Which is a lot more concise, easier to read, and is easier on your database. But doing this would prevent you from modularizing your SQL. If that is really important, you might consider storing such queries in Stored Procedure. This way, you can actually get a SP to return a list of results. Take a look at this tutorial:
http://www.wellho.net/resources/ex.php4?item=s163/stp4
Of course, that doesn't really solve your problem of being able to access variables at the lower levels of a sub select, but it would make your SQL easier to manage, and make it available to other language implementations, as you mentioned might be a need for you.
Something else to consider, in the bigger picture, would be migrating to a PHP framework that provides an ORM layer, where you could make those tables into objects, and then be able to access your data with much greater ease and flexibility (usually). But that is very 'big picture' and might not be suitable for your project requirements. One such framework that I could recommend, however, is CakePHP.
SQL query to mysql (Subquery does not recognize outer table)
The reason for your error is that you cannot access outer columns from inside a derived table (your from (...) as a
). To do it, you have to write something like (...) as a where a.tid = dancer.tid
, so you put the where
outside of the derived table; but you obviously have to rewrite a
in a way to have tid
as a column.
In your case, it would be more complicated to fix your code, so I wrote you an (easier) new one:
select tid,
CONCAT_WS("",
(SELECT GROUP_CONCAT(d2d2.taid,"---")
from dance2dancer d2d2
where d2d2.tid = d2d.tid
group by d2d2.tid limit 10),
REPEAT(",0---",10-count(distinct d2d.taid))
) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid
And a warning: this kind of query (using group_concat or concat in a column) is only to be used in a final step to format the data you want to display. If you plan to use it in another query, e.g. something like select * from dancer where INSTR('213---,345---,111---', taid) > 0
, please don't, just rewrite it.
Update without using limit 10
:
Although limit 10
should work with group_concat (it works for me), in case it doesn't work for you, you can of course just concat everything and then take the first 10 entries of the concated string afterwards. It would actually simplify the query, since you don't need the subquery anymore (that only was there to have the limit
in the first place), but might generate a large temporary string (before substring_index
) if you have a dance with A LOT of dancers.
select tid,
SUBSTRING_INDEX(CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-count(distinct d2d.taid)),
','
), ',',10) as `AllDancerWhoDance`
from dance2dancer d2d
group by d2d.tid;
or calculate a rownumber beforehand and just take the first 10 rows per tid:
select d2d.tid, CONCAT_WS("",
GROUP_CONCAT(d2d.taid,"---"),
REPEAT(",0---",10-d2d.cnt)
) as `AllDancerWhoDance`
from
(select tid, taid,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
and d2d4.taid <= d2d3.taid
) as rownum,
(select count(*)
from dance2dancer d2d4
where d2d4.tid = d2d3.tid
) as cnt
from dance2dancer d2d3
) as d2d
where d2d.rownum <= 10
group by d2d.tid;
MySQL reference outer table alias in subquery error
I think you are trying to fetch latest 7 comments for each post. Could you try this? you can test here http://www.sqlfiddle.com/#!2/a222e/3/0
The First Attempt
I tried below SQL.
SELECT *
FROM comments t1
WHERE post_id IN (247,254,244,243,242,241)
AND id IN (
SELECT id
FROM comments
WHERE t1.id = id
LIMIT 7
);
But I got an error "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery"
Another Approach
So, I tried self join on comments to generate sequence number.
SELECT id
FROM (
SELECT t1.id, COUNT(*) AS cnt
FROM comments t1 INNER JOIN comments t2
ON t1.post_id = t2.post_id
WHERE t1.id <= t2.id
AND t1.post_id IN (247,254,244,243,242,241)
AND t2.post_id IN (247,254,244,243,242,241)
GROUP BY t1.id
) x
WHERE cnt <= 7;
inner sub-query uses self join and produces cnt
column which has sequential value for each comment id of post.
But preceding query only fetches id
of comment
Finally to get all columns of comment table, following query should be executed.
SELECT *
FROM comments c INNER JOIN (
SELECT id
FROM (
SELECT t1.id, COUNT(*) AS cnt
FROM comments t1 INNER JOIN comments t2
ON t1.post_id = t2.post_id
WHERE t1.id <= t2.id
AND t1.post_id IN (247,254,244,243,242,241)
AND t2.post_id IN (247,254,244,243,242,241)
GROUP BY t1.id
) x
WHERE cnt <= 7
) t USING (id);
Using User Variables
Actually you have another chance using MySQL user variable
. I didn't mention this interesting MySQL feature because I was not sure I understood your question correctly.
SELECT *
FROM (
SELECT post_id, id,
IF (@pid = post_id, @cnt := @cnt + 1, @cnt := 1) AS cnt,
@pid := post_id
FROM comments, (SELECT @pid := 0, @cnt := 0) tmp
WHERE post_id IN (247,254,244,243,242,241)
ORDER BY post_id, id DESC
) x
WHERE cnt <= 7;
Preceding SQL looks like simpler (means good performance) than older join version. but not tested on large data set.
Related Topics
SQL Select 'N' Records Without a Table
Check If Stored Procedure Is Running
How to Set Server Output on in Datagrip
Cakephp See the Compiled SQL Query Before Execution
How to Escape a String for Use with the Like Operator in SQL Server
Sql: Select a List of Numbers from "Nothing"
Store Multiple Elements in JSON Files in Aws Athena
SQL Server Filestream Limitation
Inline Blob/Binary Data Types in SQL/Jdbc
MySQL Nested Sets - How to Find Parent of Node
Teradata SQL Pivot Multiple Occurrences into Additional Columns
Join on Set Returning Function Results
Bigquery SQL for Sliding Window Aggregate
Regular Expression to Remove Comments from SQL Statement
Reverse String Word by Word Using SQL
Pivot/Crosstab Query in Oracle 10G (Dynamic Column Number)
Extract Day of Week from Date Field in Postgresql Assuming Weeks Start on Monday
Convert 24 Hour Time to 12 Hour Plus Am/Pm Indication Oracle SQL