selecting from multiple tables vs JOIN - mysql

I need to display all fixtures(who plays 'against' who) for a current user so I wrote SQL query
SELECT
fixture.*
FROM
sport_team_player AS team_player, sport_team AS team
INNER JOIN sport_fixture AS fixture
ON (`team_player`.`team_id` = fixture.`team1_id` OR `team_player`.`team_id` = fixture.`team2_id`)
WHERE
team_player.`team_id` = team.`team_id` AND team_player.`player_id` = '16'
And this doesn't work and tells me that team_player.team_id does not exist
but if I join the second table instead of selecting from multiple tables it works just fine.
PS. This is not the best way to write such query but it's generated by ORM module..
EDIT:
Result would be list of fixture data like
------------------------------
|fixture_id|team1_id|team2_id|
------------------------------
|1 | 2 | 3 |
------------------------------

Try this one. Should result to the same query as yours;
SELECT fixture.*
FROM sport_team_player AS team_player
JOIN sport_team AS team
ON team_player.`team_id` = team.`team_id` AND team_player.`player_id` = '16'
INNER JOIN sport_fixture AS fixture
ON (`team_player`.`team_id` = fixture.`team1_id`
OR `team_player`.`team_id` = fixture.`team2_id`)
You shouldn't mix up both notations when building up joins. The comma you are using to join team_player and team , and the subsequent calls to inner join, will most probably trigger unknown column error.

Precedence of the comma operator is less than of INNER JOIN, CROSS JOIN, LEFT JOIN. That's why when you mix comma with other join table operators [Unknown column 'col_name' in 'on clause'] error occur. Same query will work if you specify the cross join ( to get a Cartesian product of the first two tables) instead of commas, because then in the from clause the table operators will be evaluated from left to right:
SELECT
fixture.*
FROM
sport_team_player AS team_player
cross join sport_team AS team
INNER JOIN sport_fixture AS fixture
ON (team_player.team_id = fixture.team1_id OR team_player.team_id = fixture.team2_id)
WHERE
team_player.team_id = team.team_id AND team_player.player_id = '16'

E.g.:
SELECT f.*
FROM sport_team_player p
JOIN sport_team t
ON t.team_id = p.team_id
JOIN sport_fixture f
ON p.team_id IN(f.team1_id,f.team2_id)
WHERE p.player_id = 16;

Related

MySQL combine multiple SELECT and JOIN [duplicate]

I have the following MySQL query:
SELECT p.*,
IF(COUNT(ms.PropertyID) > 0,1,0) AS Contacted,
pm.MediaID,
date_format(p.AvailableFrom, '%d %b %Y') AS 'AvailableFrom',
astext(pg.Geometry) AS Geometry
FROM property p, propertygeometry pg
JOIN shortlist sl ON sl.PropertyID = p.id AND sl.MemberID = 384216
LEFT JOIN message ms ON ms.PropertyID = p.id AND ms.SenderID = 384216
LEFT JOIN property_media pm ON pm.PropertyID = p.id AND pm.IsPrimary = 1
WHERE p.paused = 0
AND p.PropertyGeometryID = pg.id
GROUP BY p.id
And I'm getting this error:
#1054 - Unknown column 'p.id' in 'on clause'
As far as I can see the query looks right, any idea what could be wrong?
Don't mix ANSI-89 style and ANSI-92 style joins. They have different precedence which can lead to confusing errors, and that is what has happened here. Your query is being interpreted as follows:
FROM property p, (
propertygeometry pg
JOIN shortlist sl ON sl.PropertyID = p.id AND sl.MemberID = 384216
...
)
In the above, the joins using the JOIN keyword are evaluated first before the comma-style join is even considered. At that point the table p isn't yet declared.
From the MySQL manual:
However, the precedence of the comma operator is less than of INNER JOIN, CROSS JOIN, LEFT JOIN, and so on. If you mix comma joins with the other join types when there is a join condition, an error of the form Unknown column 'col_name' in 'on clause' may occur. Information about dealing with this problem is given later in this section.
I'd recommend always using ANSI-92 style joins, i.e. using the JOIN keyword:
SELECT p.*,
IF(COUNT(ms.PropertyID) > 0,1,0) AS Contacted,
pm.MediaID,
date_format(p.AvailableFrom, '%d %b %Y') AS 'AvailableFrom',
astext(pg.Geometry) AS Geometry
FROM property p
JOIN propertygeometry pg ON p.PropertyGeometryID = pg.id
JOIN shortlist sl ON sl.PropertyID = p.id AND sl.MemberID = 384216
LEFT JOIN message ms ON ms.PropertyID = p.id AND ms.SenderID = 384216
LEFT JOIN property_media pm ON pm.PropertyID = p.id AND pm.IsPrimary = 1
WHERE p.paused = 0
GROUP BY p.id
Related:
Why isn't SQL ANSI-92 standard better adopted over ANSI-89?
As stated before there is a precedence issue using joins via the comma operator where the LEFT JOIN will be executed and so references to table aliases won't exist at that time. Though you can implicitly tell MySQL to use a JOIN via that statement you may also tell MySQL to evaluate the comma joined tables first, then execute left join thusly:
SELECT p.*,
IF(COUNT(ms.PropertyID) > 0,1,0) AS Contacted,
pm.MediaID,
date_format(p.AvailableFrom, '%d %b %Y') AS 'AvailableFrom',
astext(pg.Geometry) AS Geometry
FROM (property p, propertygeometry pg)
JOIN shortlist sl ON sl.PropertyID = p.id AND sl.MemberID = 384216
LEFT JOIN message ms ON ms.PropertyID = p.id AND ms.SenderID = 384216
LEFT JOIN property_media pm ON pm.PropertyID = p.id AND pm.IsPrimary = 1
WHERE p.paused = 0
AND p.PropertyGeometryID = pg.id
GROUP BY p.id
Notice the comma separated tables are contained within parenthesis (). The table aliases and columns will now be available to your other JOINs.
I bumped into this error unknown column, the diff is the query is built thru HQL inside session.executeQuery("select id, name, sum(paid), custType from cust group by brand") that's why having to manually type inner join or join keyword is not an option as the hql is the one generating it.
it produces a query sumthing like this:
select cust_id, name, sum(paid), c.custTypeId
from customer c, custType ct
on c.custTypeId = ct.custTypeId
it says "unknown c.custTypeId" column when I am 101% sure it bears that column.
My classes/relations:
Customer {
Integer custId
CustomerType custType
}
CustomerType{
Integer custTypeId
string code
}
the problem lies in the comma in "from customer, custType" line. it should be with the word JOIN as the answer stated above. but since it is HQL and is being generated, I can't do that. What I did is modified by query and instead of typing select custType, I typed select custType.id, custType.code
I know it's basic but for first timers like me, it was a struggle.
If this helps someone (and a note to future myself), I was getting this error when trying to execute the following queries in MariaDB:
SELECT a.name, b.name
FROM `cities` as a
INNER JOIN `countries` as b
ON `a.country_id` = `b`.`id`;
whereas I should have written it like:
SELECT a.name, b.name
FROM `cities` as a
INNER JOIN `countries` as b
ON `a`.`country_id` = `b`.`id`;
I'll leave it to the reader to spot the difference as an exercise. :)

Error # 1066 - not a unique table / alias in MySQL

Good afternoon, I’m trying to fulfill the request while writing an error. Error # 1066 does not quite understand how it can be fixed in my particular case. Perhaps the problem is that I connect to the table several times and need an alias.
SELECT `employees`.`name`, `employees`.`surname`, `employees`.`patronymic`,
`doc`.`name`, `doc`.`agreement`, `tank`.`name`,
`liquid`.`name`, `WorkPlan`.`description`
FROM `WorkPlan` , `employees` , `doc` , `tank` , `liquid`
LEFT JOIN `WorkPlan` ON `tank`.`id` = `WorkPlan`.`id_tank`
LEFT JOIN `WorkPlan` ON `liquid`.`id` = `WorkPlan`.`id_liquid`
LEFT JOIN `WorkPlan` ON `doc`.`id` = `WorkPlan`.`id_doc`
AND `WorkPlan`.`id_tank` = `tank`.`id`
AND `WorkPlan`.`id_liquid` = `liquid`.`id`
AND `WorkPlan`.`id_doc` = `doc`.`id`
I suspect (by your SELECT list of columns) that you want to join employees to the other tables.
For every join you must specify in the ON clause the columns that relate the 2 tables and it is a good practice to use aliases for the tables which shorten the code and make it more readable:
SELECT e.name, e.surname, e.patronymic,
d.name, d.agreement,
t.name,
l.name,
w.description
FROM employees e
LEFT JOIN WorkPlan w ON e.? = w.?
LEFT JOIN tank t ON t.id = w.id_tank
LEFT JOIN liquid l ON l.id = w.id_liquid
LEFT JOIN doc d ON d.id = w.id_doc
Replace the ? with the names of the columns that relate employees with WorkPlan.

how to join SQL with 3 tables

I'm trying to study SQL.
I have a problem with JOIN
I want to display ref_id, pro_name, class_name but I couldn't.
I find EFFICIENT solution.
MY QUERY (DOESN'T WORK)
SELECT
ref_id, pro_name, class_name
FROM
RC, RP, PP, LP
WHERE
RC.ref_id = RP.ref_id
Avoid using commas be CROSS JOIN
You could use JOIN to instead of commas
like this.
SELECT
RP.ref_id, PP.pro_name, LP.class_name
FROM
RP
LEFT JOIN RC ON RC.ref_id = RP.ref_id
LEFT JOIN PP ON PP.pro_id = RP.pro_id
LEFT JOIN LP ON LP.lec_id = RP.lec_id
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
You would seem to want:
select rp.pro_id, pp.pro_name, lp.class_name
from rp left join
pp
on rp.pro_id = pp.pro_id left join
lp
on rp.lec_id = lp.lec_id;
Note the use of left join. This ensure that all rows are in the result set, even when one or the other joins doesn't find a matching record.
From what I can see, the table rc is not needed to answer this specific question.

SQL Join with Value Missing in One Column

I'm trying to create a SQL query that uses one table to count the number of blade servers our company has in each chassis and groups those, while joining it with chassis information from another table.
However, one of the chassis has no blades in it, so the name does not appear in the blade inventory table. Using an INNER JOIN creates a table that doesn't contain that blade in any capacity. A LEFT JOIN achieves the same effect, but a RIGHT JOIN gives me an extra row with a null value for the chassis name.
I'm guessing this is because the non-existence of that blade name in the first table is being given precedence over the second, but not sure how to correct that. My query, as of now, looks like this:
SELECT e.EnclosureName, e.PDUName, q.Blades, r.Serial#
FROM bladeinventory.table e JOIN
(
SELECT EnclosureName,COUNT(*) Blades
FROM bladeinventory.table
GROUP BY EnclosureName
) q ON e.EnclosureName = q.EnclosureName
LEFT JOIN chassisinventory.table r
ON e.EnclosureName = r.EnclosureName
GROUP BY e.EnclosureName, e.PDUName, q.Blades, r.Serial#
Is it possible to edit this in such a way that the name of the chassis with 0 blades is actually generated by the query?
Just pull the name from the chassisinventory table. I'll use coalesce(), just in case you switch the order of the joins (again):
SELECT COALESCE(r.EncloseName, e.EnclosureName) as EnclosureName, e.PDUName, q.Blades, r.Serial#
FROM bladeinventory.table e JOIN
(SELECT EnclosureName,COUNT(*) Blades
FROM bladeinventory.table
GROUP BY EnclosureName
) q
ON e.EnclosureName = q.EnclosureName LEFT JOIN
chassisinventory.table r
ON e.EnclosureName = r.EnclosureName
GROUP BY COALESCE(r.EncloseName, e.EnclosureName), e.PDUName, q.Blades, r.Serial#;
You can also use below code where case is being used which is much simpler and effective
SELECT e.EnclosureName, r.PDUName,
case when q.Blades IS NULL then 0
else q.Blades end Blades,
e.Serial#
FROM chassisinventory.table e
LEFT OUTER JOIN bladeinventory.table r on e.EnclosureName = r.EnclosureName
LEFT OUTER JOIN (SELECT EnclosureName,COUNT(*) Blades
FROM bladeinventory.table
GROUP BY EnclosureName
) q on e.EnclosureName = q.EnclosureName

Optimizing a where statement MYSQL

Im writing this complex query to return a large dataset, which is about 100,000 records. The query runs fine until i add in this OR statement to the WHERE clause:
AND (responses.StrategyFk = strategies.Id Or responses.StrategyFk IS
Null)
Now i understand that by putting the or statement in there it adds a lot of overhead.
Without that statement and just:
AND responses.StrategyFk = strategies.Id
The query runs within 15 seconds, but doesn't return any records that didn't have a fk linking a strategie.
Although i would like these records as well. Is there an easier way to find both records with a simple where statement? I can't just add another AND statement for null records because that will break the previous statement. Kind of unsure of where to go from here.
Heres the lower half of my query.
FROM
responses, subtestinstances, students, schools, items,
strategies, subtests
WHERE
subtestinstances.Id = responses.SubtestInstanceFk
AND subtestinstances.StudentFk = students.Id
AND students.SchoolFk = schools.Id
AND responses.ItemFk = items.Id
AND (responses.StrategyFk = strategies.Id Or responses.StrategyFk IS Null)
AND subtests.Id = subtestinstances.SubtestFk
try:
SELECT ... FROM
responses
JOIN subtestinstances ON subtestinstances.Id = responses.SubtestInstanceFk
JOIN students ON subtestinstances.StudentFk = students.Id
JOIN schools ON students.SchoolFk = schools.Id
JOIN items ON responses.ItemFk = items.Id
JOIN subtests ON subtests.Id = subtestinstances.SubtestFk
LEFT JOIN strategies ON responses.StrategyFk = strategies.Id
That's it. No OR condition is really needed, because that's what a LEFT JOIN does in this case. Anywhere responses.StrategyFk IS NULL will result in no match to the strategies table, and it wil return a row for that.
See this link for a simple explanation of joins: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
After that, if you're still having performance issues then you can start looking at the EXPLAIN SELECT ... ; output and looking for indexes that may need to be added. Optimizing Queries With Explain -- MySQL Manual
Try using explicit JOINs:
...
FROM responses a
INNER JOIN subtestinstances b
ON b.id = a.subtestinstancefk
INNER JOIN students c
ON c.id = b.studentfk
INNER JOIN schools d
ON d.id = c.schoolfk
INNER JOIN items e
ON e.id = a.itemfk
INNER JOIN subtests f
ON f.id = b.subtestfk
LEFT JOIN strategies g
ON g.id = a.strategyfk