mysql joins are driving me mad! - mysql

So I've asked a couple of questions about performing joins and have had great answers, but there's still something I'm completely stumped by.
I have 3 tables. Let us call them table-b, table-d and table-e.
Table-b and table-d share a column called p-id.
Table-e and table-b share a column called ev-id.
Table-e also has a column called date.
Table-b also has a unique id column called u-id.
I'd like to write a query which returns u-id under the following conditions:
1) Restriced to a certain value in table-e.date.
2) Where table-b.p-id does not match table-d.p-id.
I think I need to inner join table-b and and table-e on the e-id column. I then think I need to perform a left join on table-d and and table-b where p-id is null.
My problem is that I don't know the syntax of writing this query. I know how to write multiple inner joins and I know how to write a left join. How do I combine the two?
Thanks so much to everyone who is helping me out. I'm (obviously!) a newbie to databases and am struggling to get my head around it all!

You just write the joins one after the other:
SELECT b.uid
FROM b
INNER JOIN e USING(evid)
LEFT JOIN d USING(pid)
WHERE e.date = :whatever
AND d.pid IS NULL

I think it's something like this:
SELECT uid
FROM table-b
INNER JOIN table-e
ON table-b.ev_id = table-e.ev_id
WHERE table-b.p_id NOT IN (SELECT p_id from table-d)

Related

PHP Queries not working

This is working:
SELECT *
FROM ((((defect
JOIN project_testcase ON
defect.Test_Id=project_testcase.Test_Id)
JOIN testcase ON
defect.Test_Id=testcase.Test_Id)
JOIN project_pm ON
project_testcase.Project_Id=project_pm.Project_Id)
JOIN employee ON
employee.Emp_id=project_pm.Emp_id)
However, this does not work:
SELECT *
FROM ((((defect
JOIN project_testcase ON
defect.Test_Id=project_testcase.Test_Id)
JOIN testcase ON
defect.Test_Id=testcase.Test_Id)
JOIN project_pm ON
project_testcase.Project_Id=project_pm.Project_Id)
JOIN employee ON
employee.Emp_id=project_pm.Emp_id)
WHERE Project_Id LIKE '%$categ%'
As I have used JOIN tables and joined using Project_Id. Is that the error?
The first thing I would do to troubleshoot this is to paste it into an SQL formatter. This will help find syntax errors and could help you see a logic error. I would recommend freeformatter.com.
Second you can get rid of the parenthesis.
The Fix
You need to specify what table to get the Project_Id in the WHERE because it is in multiple tables, but for clarity I would always specify what table it comes from.
select
*
from
defect
join
project_testcase
on defect.Test_Id=project_testcase.Test_Id
join
testcase
on defect.Test_Id=testcase.Test_Id
join
project_pm
on project_testcase.Project_Id=project_pm.Project_Id
join
employee
on employee.Emp_id=project_pm.Emp_id
where
project_testcase.Project_Id like '%$categ%'
Project_Id in the where clause is ambiguous, you need to define it as you have done on your joins ie WHERE project_pm.Project_Id like '%$categ%'
In the where clause of the 2nd query you need to tell the rdbms exactly which Project_Id field you want to filter on, since multiple tables contain the Project_Id field, e.g. project_pm.Project_Id.
Starting by removing all those unnecessary parenthesis, formatting and aliases reveals a fairly simple query underneath.
select * --This should really be the columns you actually need instead of all of them
from defect d
join project_testcase ptc on d.Test_Id = ptc.Test_Id
join testcase t on d.Test_Id = t.Test_Id
join project_pm p on ptc.Project_Id = p.Project_Id
join employee e on e.Emp_id = p.Emp_id
where p.Project_Id like '%$categ%'
Of course this begs the question of why do you have text like that in a column named Project_Id? That does not look like a project id to me. And since you are using a leading wildcard you have a nonSARGable query so you have eliminated the ability of index seeks on that column.

Difference between FROM and JOIN tables

I'm working through the JOIN tutorial on SQL zoo.
Let's say I'm about to execute the code below:
SELECT a.stadium, COUNT(g.matchid)
FROM game a
JOIN goal g
ON g.matchid = a.id
GROUP BY a.stadium
As it happens, it produces the same output as the code below:
SELECT a.stadium, COUNT(g.matchid)
FROM goal g
JOIN game a
ON g.matchid = a.id
GROUP BY a.stadium
So then, when does it matter which table you assign at FROM and which one you assign at JOIN?
When you are using an INNER JOIN like you are here, the order doesn't matter. That is because you are connecting two tables on a common index, so the order in which you use them is up to you. You should pick an order that is most logical to you, and easiest to read. A habit of mine is to put the table I'm selecting from first. In your case, you're selecting information about a stadium, which comes from the game table, so my preference would be to put that first.
In other joins, however, such as LEFT OUTER JOIN and RIGHT OUTER JOIN the order will matter. That is because these joins will select all rows from one table. Consider for example I have a table for Students and a table for Projects. They can exist independently, some students may have an associated project, but not all will.
If I want to get all students and project information while still seeing students without projects, I need a LEFT JOIN:
SELECT s.name, p.project
FROM student s
LEFT JOIN project p ON p.student_id = s.id;
Note here, that the LEFT JOIN refers to the table in the FROM clause, so that means ALL of students were being selected. This also means that p.project will be null for some rows. Order matters here.
If I took the same concept with a RIGHT JOIN, it will select all rows from the table in the join clause. So if I changed the query to this:
SELECT s.name, p.project
FROM student s
RIGHT JOIN project p ON p.student_id = s.id;
This will return all rows from the project table, regardless of whether or not it has a match for students. This means that in some rows, s.name will be null. Similar to the first example, because I've made project the outer joined table, p.project will never be null (assuming it isn't in the original table). In the first example, s.name should never be null.
In the case of outer joins, order will matter. Thankfully, you can think intuitively with LEFT and RIGHT joins. A left join will return all rows in the table to the left of that statement, while a right join returns all rows from the right of that statement. Take this as a rule of thumb, but be careful. You might want to develop a pattern to be consistent with yourself, as I mentioned earlier, so these queries are easier for you to understand later on.
When you only JOIN 2 tables, usually the order does not matter: MySQL scans the tables in the optimal order.
When you scan more than 2 tables, the order could matter:
SELECT ...
FROM a
JOIN b ON ...
JOIN c ON ...
Also, MySQL tries to scan the tables in the fastest way (large tables first). But if a join is slow, it is possible that MySQL is scanning them in a non-optimal order. You can verify this with EXPLAIN. In this case, you can force the join order by adding the STRAIGHT_JOIN keyword.
The order doesn't always matter, I usually just order it in a way that makes sense to someone reading your query.
Sometime order does matter. Try it with LEFT JOIN and RIGHT JOIN.
In this instance you are using an INNER JOIN, if you're expecting a match on a common ID or foreign key, it probably doesn't matter too much.
You would however need to specify the tables the correct way round if you were performing an OUTER JOIN, as not all records in this type of join are guaranteed to match via the same field.
yes, it will matter when you will user another join LEFT JOIN, RIGHT JOIN
currently You are using NATURAL JOIN that is return all tables related data, if JOIN table row not match then it will exclude row from result
If you use LEFT / RIGHT {OUTER} join then result will be different, follow this link for more detail

sql/Mysql: What is the best method to complete this query

I had most of this query worked about except two things, large things, one, as soon as I add the forth table [departments_tbl]into the query, I get about 8K rows returned when I should only have about 100.
See the attached schema, no the checkmarks, these are the fields I want returned.
This won't help, but here is just one of the queries that I almost had working, until the [department_tbl was added to the mix]
SELECT _n_cust_entity_storeid_15.entity_id,
_n_cust_entity_storeid_15.email,
customer_group.customer_group_code,
departments.`name`,
departments.manager,
_n_cust_rpt_copy.first_name,
_n_cust_rpt_copy.last_name,
_n_cust_rpt_copy.last_login_date,
_n_cust_rpt_copy.billing_address,
_n_cust_rpt_copy.billing_city,
_n_cust_rpt_copy.billing_state,
_n_cust_rpt_copy.billing_zip
FROM _n_cust_entity_storeid_15 INNER JOIN customer_group ON _n_cust_entity_storeid_15.group_id = customer_group.customer_group_id
INNER JOIN departments ON _n_cust_entity_storeid_15.store_id = departments.store_id,
_n_cust_rpt_copy
ORDER BY _n_cust_rpt_copy.last_name ASC
I've tried subqueries, joins, but just can't get it to work.
Any help would be greatly appreciated.
Schema Please note that entity_id and cust_id fields would the be links between the _ncust_rpt_copy table and the _n_cust_entity_storeid_15 tbl
You have a cross join to the last table, _n_cust_rpt_copy:
SELECT _n_cust_entity_storeid_15.entity_id,
_n_cust_entity_storeid_15.email,
customer_group.customer_group_code,
departments.`name`,
departments.manager,
_n_cust_rpt_copy.first_name,
_n_cust_rpt_copy.last_name,
_n_cust_rpt_copy.last_login_date,
_n_cust_rpt_copy.billing_address,
_n_cust_rpt_copy.billing_city,
_n_cust_rpt_copy.billing_state,
_n_cust_rpt_copy.billing_zip
FROM _n_cust_entity_storeid_15 INNER JOIN
customer_group
ON _n_cust_entity_storeid_15.group_id = customer_group.customer_group_id INNER JOIN
departments
ON _n_cust_entity_storeid_15.store_id = departments.store_id join
_n_cust_rpt_copy
ON ???
ORDER BY _n_cust_rpt_copy.last_name ASC;
It is not obvious to me what the right join conditions are, but there must be something.
I might guess they it at least includes the department:
_n_cust_rpt_copy
ON _n_cust_rpt_copy.department_name = departments.name and

Join of tables returning incorrect results

There are 4 sql tables:
Listings(Amount, GroupKey, Key, MemberKey),
Loans(Amount, GroupKey, Key, ListingKey),
Members(City, GroupKey, Key)
Groups(GroupRank, Key, MemberKey)
Now, if one wants to find out the loans which are also listings and find the members city and GroupRank for the members in the loan table. Here, the group table contains information about grous of which members are a part of.
and also perform a select operation as given below:
select Listings.Amount, Members.City, Groups.GroupRank
from listings, loans, members, groups
where Listings.Key=Loans.ListingKey and
Members.Key=Listings.MemberKey and
Listings.GroupKey=Groups.Key
The above join is giving an incorrect result, please point out where I am going wrong.
Also I am new to SQL so please excuse the novice question.
Note: The following is just a guess what your problem is. Like others said, clearify your question.
You want to JOIN
( http://dev.mysql.com/doc/refman/5.1/de/join.html )
those tables. What you write is just another form of a join, meaning it has the same effect. But you "joined" a bit too much. To make things clearer a syntax has been invented to make things clearer and avoid such mistakes. Read more about it in the link given above.
What you want to achieve can be done like this:
SELECT
Listings.Amount, Members.City, Groups.GroupRank
FROM
Listings
INNER JOIN Groups ON Listings.GroupKey=Groups.Key
INNER JOIN Members ON Members.Key=Listings.MemberKey
You don't do a SELECT on the Loans table, you don't need it in this query.
This is the INNER JOIN which will give you a result where every row in table A has an according entry in table B. When this is not the case, you have to use the LEFT or RIGHT JOIN.
Maybe the problem is related to the join type (INNER). Try LEFT JOIN for example but Mark has right: you should clearify your question.
I would firstly change your query to use the more modern join syntax, which allows outer joins. Tr this:
select Listings.Amount, Members.City, Groups.GroupRank
from listings
left join loans on Listings.Key=Loans.ListingKey
left join members on Members.Key=Listings.MemberKey
left join groups on Listings.GroupKey=Groups.Key
and/or Loans.GroupKey=Groups.Key
and/or Members.Key=Groups.MemberKey
You may need to play with the criteria on the last join (maybe they should be "or" not "and" etc).

Geting the last entry on join

So, I have these 2 tables. One contains, lets call them, bugs, and another contains solutions. One bug may have more than one solution (or state, if you may), and I'd like to get the last one.
Right now, I'm doing it like this:
Select b.*, ap.approveMistakeId
from bugs_table as b
LEFT JOIN (select approveId, approveCause, approveDate, approveInfo,
approveUsername, mistakeId as approveMistakeId
from approve_table
order by approveDate desc) AS ap
ON m.mistakeId = ap.approveMistakeId
GROUP BY b.bugId
This is not a complete query, it is just to show the how I'm approaching it. The real query joins more than 10 tables.
The problem with this is, that with this subselect, the query runs for about 3.3s and returns ~2.4K records. Without this query, it runs for 0.4s, which is more acceptable. I have created and index on approveDate, but that didn't seem to solve the problem.
Could the solution be a view, that was created from this query, and then joined to this query? Or is there a way to do this in some other manner?
Thanks!
For joining two tables, you essentially should have some join condition. If I take m.mistakeId = ap.approveMistakeId to be b.mistakeId = ap.approveMistakeId, then also you can go for a simpler join like:
Select b.*, ap.approveMistakeId, ap.approveDate
from bugs_table as b
INNER JOIN approve_table as ap ON b.mistakeId = ap.approveMistakeId
order by ap.approveDate desc
The problem was the sub-select. The solution - de-normalization. Yes, I know, that isn't the best solution, but definitely the fastest.
Tried aggregate self-sorting, but that only added time. Same with joining with a view.