Accessing table from a sub-query inside an inner join - MySql - mysql

I am having an SQL query as follows -
select
*
from A
inner join AA on A.id = AA.aid
inner join AAA on
(
select B.bid, B.bname
from B
inner join C on B.id = C.bid
where C.aaid = AA.id
) as B1 on A.id = B1.aid
Which gives an error
Unknown column 'AA.id' in 'where clause'
It will be very helpful if someone can tell me the reason and provide me with a possible solution.

I believe that you need something like this
select
*
from A
inner join AA on A.id = AA.aid
inner join AAA on AA.id = AAA.aid
inner join
(
select B.bid, B.bname, C.aaid
from B
inner join C on B.id = C.bid
) as B1 on A.id = B1.aid and AA.id = B1.aaid
It is not possible to reference outer aliases in join subqueries in MySQL. In PostgreSQL you could use CROSS JOIN LATERAL and in SQL Server CROSS APPLY, however, there is no such thing in MySQL.

From my understanding,
select
*
from #a1 a1 --A
inner join #a2 a2 on a1.i = A2.i --AA
inner join #a3 a3 on a1.i = a3.i --AAA
inner join
(
select B.i, a2.i ai
from #b b --B
inner join #c c on B.i = C.i --C
inner join #a2 a2 on a2.i = C.i --AA
) as B1
on A1.i = B1.i
and B1.ai = a2.i
Lack of sample data, we help as assumption.
Revert me, if query needs updates.

This is too long for a comment, so ...
Let's say you didn't write the subquery in the FROM clause as an ad-hoc view, but make it an explicit view B1 (with CREATE VIEW). Then your query would read
select *
from A
inner join AA on A.id = AA.aid
inner join AAA on B1 on A.id = B1.aid
which illustrates that your syntax is off.
Moreover the B1 select doesn't contain an aid, only a bid and a bname.
At last the ON clause for AAA doesn't contain any reference to the table AAA, so this is not really a join criteria for that table.
This is the answer to what's wrong with your query. I cannot show you the correct query, though, because it's completely unclear what you are trying to achieve. Please elaborate. It's probably quite simple and you're over-complicating things :-)

Related

Need help writing an inner join query

$query= mysqli_query($db,"SELECT a.*, b.collection_id , c.contract_id,
d.customer_name FROM rentals_invoice
AS b INNER JOIN rental_collection as a ON (b.collection_id = a.collection_id)
AS c INNER JOIN rental_contract as b ON (c.contract_id = b.contract_id)
AS d INNER JOIN customer_info as c ON (d.customer_id = c.customer_id)");
I have tables a, b, c, d
'a' have fkey of 'b'
'b' have fkey of 'c'
'c' have fkey of 'd'
I want to get data from all of them, and I don't know how to get it through inner join or any other type of join in a single query.
I am a beginner.
You have misplaced your aliases. You are overwriting your aliases. You also can use the using to simplify this.
FROM rentals_invoice AS b
INNER JOIN rental_collection as a using(collection_id)
INNER JOIN rental_contract AS c using(contract_id)
INNER JOIN customer_info as d using(customer_id)");
I also would use aliases that relate to the actual table name. a, b, c, etc. aren't useful and will be hard to diagnose later.
$query = mysqli_query($db,"
SELECT a.*,b.collection_id,c.contract_id,d.customer_name
FROM `rentals_invoice` As a
INNER JOIN rental_collection As b ON b.collection_id = a.collection_id
INNER JOIN rental_contract AS c ON c.contract_id = b.contract_id
INNER JOIN customer_information AS d ON d.customer_cnic = c.customer_cnic
");
Thanks to all who helped or tried to help me, i got the understanding of JOIN.

How does multiple "ON" in a JOIN statement works

I'm currently reading a query that I don't usually see in some other queries when joining tables.
SELECT
*
FROM table_1
RIGHT OUTER JOIN table_2
INNER JOIN table_3
ON table_2.some_id = table_3.some_id
RIGHT OUTER JOIN table_4
ON table_3.some_id = table_4.some_id
LEFT OUTER JOIN table_5
ON table_4.some_id = table_5.some_id
ON table_1.some_id = table_4.some_id
Please don't mind how those tables being joined. I just want to know how did that query works? Thank you in advance.
I think the SQL Server documentation captures what is happening better than MySQL. (Here is the documentation.)
This is a parsing issue, as Laurence has observed. You can understand what is by looking at the syntax diagram for the from statement. There is a recursive reference that most people never think about (including me). A joined table has the following syntax:
<joined_table> ::=
{
<table_source> <join_type> <table_source> ON <search_condition>
| <table_source> CROSS JOIN <table_source>
| left_table_source { CROSS | OUTER } APPLY right_table_source
| [ ( ] <joined_table> [ ) ]
}
The key here is the first piece, <table_source> <join_type> <table_source>. Well, guess what, a table_source can be a joined_table (as well as a bunch of other things). This means that the syntax:
A join B join C ON <condition1> ON <condition2>
Fits the grammar above and is interpreted as:
A join (B join C on <condition1>) ON <condition2>
That is, the expression B join C on <condition1> is treated as a "table_source".
My guess is that if both SQL Server and MySQL do it this way, then it is probably part of the standard. However, the standard is a bit harder to understand than SQL Server's syntax diagrams.
I think this is down to the way right outer join is evaluated:
Select
*
from
a
right outer join
b
inner join
c
on b.id = c.id
on a.id = b.id;
is evaluated as
Select
*
from
a
right outer join (
b
inner join
c
on b.id = c.id
)
on a.id = b.id;
Mixing left and right outer join is a path to madness.
The OP's query seems to be driven by a desire to exclude parenthesis, or derived tables. It is equivalent to:
Select
a.id ida,
b.id idb,
c.id idc,
d.id idd,
e.id ide
From
D
left outer join
A
on d.id = a.id
left outer join
E
on d.id = e.id
left outer join (
B
inner join
C
on b.id = c.id
)
on d.id = b.id;
Example SQLFiddle

left join optimisation

I have a database similar to the simplified one below. I need to retrieve columns: col8, col9, col10, col11, col12 (the ones I've circled
Currently, I;m using a left join to join each table but this results in the query taking a very long (there are lots of records). Upon profiling, the biggest impact is writing to the tmp table.
I'm limiting the result to 24, but because of the left joins it's still copying thousands of records to the tmp table.
http://oberto.co.nz/demo/assets/db2.jpeg
Can this be optimised to still retrieve the circled column from each table using joining by the pk?
Thanks.
SELECT a.col12, b1.col8, c1.col9, d1.col10, e1.col11
FROM a
INNER JOIN (SELECT b.col8, b.col2, b.col3 FROM b
WHERE b.col2 = a.col2 GROUP BY b.col8) b1
ON (b1.col2 = a.col2)
INNER JOIN (SELECT c.col9, c.col3, c.col4 FROM c
WHERE c.col3 = b1.col3 GROUP BY c.col9) c1
ON (c1.col3 = b1.col3)
INNER JOIN (SELECT d.col10, d.col4 FROM d
WHERE d.col4 = c1.col4 GROUP BY d.col10) d1
ON (d1.col4 = c1.col4)
INNER JOIN (SELECT e.col11, e.col6 FROM e
WHERE e.col6 = a.col6 GROUP BY e.col11) e1
ON (e1.col6 = a.col6)
Now you will have no more duplicate rows.
You may have to experiment with LEFT instead of INNER joins.
And if you don't need a subselect you should eliminate it, because it slows things down.
in its current and simplest form, I would have the query as...
SELECT STRAIGHT_JOIN
a.col1,
a.col12,
b.col8,
c.col9,
d.col10,
e.col11
FROM a
left join b
on a.col2 = b.col2
left join c
on b.col3 = c.col3
left join d
on c.col4 = d.col4
left join e
on a.col6 = e.col6
However, will adjust once I read back on other criteria, filters, conditions, left/inner join "requirements" that may help optimize further.

MySQL LEFT RIGHT JOIN syntax fluency

I'm coming across this situation alot, I'll have a query that will have one table needed in a join condition that may have no entries therefore requiring me to use a LEFT JOIN. I can't wrap my head around the syntax when it's used with more than 1 join.
I'll have:
SELECT A.*, B.*, C.*
FROM A, B, C
WHERE A.id = C.id
AND C.aid = A.id
AND B.cid = C.id
Along comes D with the possibility of being empty and I have to rewrite the query and run into problems.
How can I simply join D to any one of these tables?
You're much better off explicitly specifying all of your JOINs. That should make things much clearer.
SELECT A.*, B.*, C.*, D.*
FROM A
INNER JOIN C
ON C.aid = A.id
INNER JOIN B
ON B.cid = C.id
LEFT JOIN D
ON C.did = d.id
My advice is to never specify more than one column on FROM clause.
For clarity, it's better to always:
Use JOIN clause
Use aliases
Specify columns of joined tables on left side of equal sign
Example:
SELECT a.*, b.*, c.*
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
Not sure about MySQL, but in some other SQL flavors, you can use the same on UPDATES and DELETES, like:
DELETE FROM a
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
or
UPDATE a
SET something = newValue
FROM ATable a
INNER JOIN BTable b
ON b.id = a.id
INNER JOIN CTable c
ON c.id = a.id
WHERE a.someColumn = 'something'
The syntax below should help you. The basic premise is whatever table is listed LEFT is the required.. the table (or alias) on the right is optional. I understand you don't quite get it, and your syntax sample shows that (not meant to criticize) as you are joining from A -> C and C back to A on a different field. If this is the case where two fields are in the "C" table that BOTH point to A, you would re-join to A as a second alias...
select
Want.*,
Maybe.*,
SecondA.*,
B.*
From
A as Want
LEFT JOIN C as Maybe
on Want.ID = Maybe.ID
JOIN A as SecondA
on Maybe.AID = SecondA.ID
JOIN B
on Maybe.ID = B.cID
So, this query is stating I want everything from Table A (alias Want -- left side/first table in the list) Regardless of there being a match in Table C (alias Maybe) where the ID keys match.
Notice the next joins going down from "C" back to the second instance of "A" and table B. I have those as just joins... So the relationship between the "Maybe" alias, and that of second instance of "A" and "B" are JOIN (required).
Hopefully this gives some better clarification on HOW it works.
Now, for your real-life query. If you can describe what you are looking for, and your sample table structures / result expections, listing that could offer more explicit solution to your needs.
Hope this will help
SELECT
A.*, B.*, C.*
FROM A
inner join C on(A.id = C.id)
inner join B on(B.cid = C.id)

MySQL GROUP BY performance issue

This is the query I'm performing (without some Joins that are not relevant):
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id
Each row of "a" is linked with 1 to 5 rows in "b".
The problem is that GROUP BY has performance issues (it takes 10x or more using GROUP BY than not using it). I need to retrieve only one row of each member in "a".
How can I make this faster?
edit: I need to be able to filter by a.id AND/OR c.id. The resultset I should be getting is only 1 row per "valid" member of "a", meaning the rows that match the constraints. Rows that don't match the filters shouldn't be returned.
In my original query, this would be done this way:
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id
a.id, b.id_anunciante, b.id_rubro, c.id are all indexes.
SELECT a.*,
(
SELECT c.id
FROM b
JOIN с
ON c.id = b.id_rubro
WHERE b.id_anunciante = a.id
-- add the ORDER BY condition to define which row will be selected.
LIMIT 1
)
FROM a
Create the index on b (id_anunciante) for this to work faster.
Update:
You don't need the OUTER JOINs here.
Rewrite your query as this:
SELECT a.*, c.id
FROM a
JOIN b
ON b.id_anunciante = a.id
JOIN c
ON c.id = b.id_rubro
WHERE a.id = 1
UNION ALL
SELECT a.*, 1
FROM a
WHERE EXISTS
(
SELECT NULL
FROM c
JOIN b
ON b.id_rubro = c.id
WHERE c.id = 1
AND b.id_anunciante = a.id
)
Add ORDER BY NULL to avoid the implicit sorting MySQL does when doing a group by.
I suppose you have indexes/PKs on a.id, b.id_anunciante, b.id_rubro and c.id ? I guess you could try adding a composite index on (b.id_anunciante, b.id_rubro) if your mysql version is not able to do an index merge.