Using MySQL, I'm trying to do a JOIN similar to how you would use a JOIN with OR statements like:
JOIN bioguide ON (bioguide.fulldistrict=house.districtname) OR
(left(bioguide.firstname,3)=left(house.first,3) AND bioguide.lastname=house.last) OR
(bioguide.fulldistrict=house.districtname AND bioguide.lastname=house.last)
As you probably know, the problem with doing it this way is that if a bunch of different ways work, you get multiple results per row.
My hope is that there's a way to use the JOIN and use it the way the COALESCEfunction works, essentially stating (even though it doesn't work):
JOIN bioguide ON COALESCE(bioguide.firstname=house.first AND
bioguide.lastname=house.last),(left(bioguide.firstname,3)=left(house.first,3) AND
bioguide.lastname=house.last),(bioguide.fulldistrict=house.districtname AND
bioguide.lastname=house.last))
If that worked, it'd be telling SQL to first JOIN on (bioguide.firstname=house.first AND bioguide.lastname=house.last) then on (left(bioguide.firstname,3)=left(house.first,3) AND bioguide.lastname=house.last), etc.
Is something like this possible? Please let me know if other information would be helpful.
Thanks everybody!
You can structure the query with the different matches in different tables, and then use coalesce() in the select to get what you want:
select coalesce(bg1.col1, bg2.col2, bg3.col3)
from . . . left outer join
bioguide bg1
on bg1.fulldistrict=house.districtname left outer join
bioguide bg2
on left(bg2.firstname,3)=left(house.first,3) AND bg2.lastname=house.last left outer join
bioguide bg3
on bg3.fulldistrict=house.districtname AND bg3.lastname=house.last
This can still result in multiple rows, if there are multiple matches for one of the comparisons (if the same row in bioguide matches all three, you have no problem with duplicated rows).
If so, then judiciously use a group by:
group by <id column that identifies each row in the result set>
Related
I have the following MySQL query:
SELECT inv.inventory_id, inv.item_id, item.description, inv.quantity, item.class_id, class.description AS class,
class.is_spool, inv.location_id, location.description AS location, location.division_id, division.name AS division,
inv.service_date, inv.reel_number, inv.original_length, inv.current_length, inv.outside_sequential,
inv.inside_sequential, inv.next_sequential, inv.notes, inv.last_modified, inv.modified_by
FROM reel_inventory AS inv
INNER JOIN reel_items AS item ON inv.item_id = item.item_id
INNER JOIN reel_locations AS location ON inv.location_id = location.location_id
INNER JOIN locations AS division ON location.division_id = division.location_id
RIGHT JOIN reel_classes AS class on item.class_id = class.class_id;
The query works exactly as expected as is. What I was trying to do was add a WHERE clause to this query with one qualifier. For example:
RIGHT JOIN reel_classes AS class ON item.class_id = class.class_id
WHERE inv.current_length > 0;
When I do this, all of the results from the RIGHT JOIN are not included in the result. I've not had a ton of experience with advanced queries, but could someone explain why the RIGHT JOIN is excluded from the result set when a WHERE is used, and how to property write the query to include the RIGHT JOIN information?
Thanks in advance.
What you want is:
RIGHT JOIN reel_classes AS class
ON item.class_id = class.class_id AND
inv.current_length > 0;
Your question is why the RIGHT JOIN turns into an INNER JOIN with the WHERE clause.
The reason is simple. For the non-matching rows, inv.current_length is NULL and this fails the comparison.
I would also suggest that you use LEFT JOIN, starting with the table where you want to keep all the rows. Most people find it much easier to understand logic that is "keep all rows in the first table" rather than "keep all rows in some table whose name will come up".
I have the following tables. All fields are NOT NULL.
tb_post
id
account_id
created_at
content
tb_account
id
name
I want to select the latest post along with the name. Should I use INNER JOIN or LEFT JOIN? From my understanding both produce the same results. But which is more correct or faster?
SELECT p.content, a.name
FROM tb_post AS p
[INNER or LEFT] JOIN tb_account AS a
ON a.id = p.account_id
ORDER BY p.created_at DESC
LIMIT 50
A LEFT JOIN is absolutely not faster than an INNER JOIN. In fact, it's slower; by definition, an outer join (LEFT JOIN or RIGHT JOIN) has to do all the work of an INNER JOIN plus the extra work of null-extending the results. It would also be expected to return more rows, further increasing the total execution time simply due to the larger size of the result set.
(And even if a LEFT JOIN were faster in specific situations due to some difficult-to-imagine confluence of factors, it is not functionally equivalent to an INNER JOIN, so you cannot simply go replacing all instances of one with the other!)
Better go for INNER JOIN.
As Per My View The Correct One Is Inner join
because it returns resultset that include only matched elements where Left Join Returns all entries from Left Table. In this case I think Inner join returns the only required amount of data to be proceed.
You have to ask yourself two questions.
1) Is there any chance that at some point in your application lifetime, there will be posts with an empty or invalid account_id?
If not, it doesn't matter.
If yes...
2) Would it be desirable to include posts without an associated account in the result of the query? If yes, use LEFT JOIN, if no, use INNER JOIN.
I personally don't think speed is very relevant: the difference between them is what they do.
They happen to give the same result in your case, but that does not mean they can be interchanged, because choosing the one or the other still tells the other guy that reads your code something.
I tend to think like this:
INNER JOIN - the two tables are basically ONE set, we just need to combine two sources.
LEFT JOIN - the left tables is the source, and optionally we may have additional information (in the right table).
So if I would read your code and see a LEFT JOIN, that's the impression you give me about your data model.
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
I have a problem with the following SQL Query. As you can see, I join some tables (candidate_basic,candidate_lang,province_of_candidate,province,degree_of_candidate), and then I join the result with another table "professional_experience_basic" but, the query return several instances (example: it returns two instances for id_candidate_basic=55, or it returns three instances of id_candidate_basic=59).
My problem is that I only want that the query return 1 instance per id_candidate_basic. That is, the instance with attribute "main_job" with value 1, and if this is not possible, just a null.
I tried to put AND professional_experience_basic.main_job=1 inside the WHERE clause, but, it remove the instances with main_job=null.
I feel that I'm close to the final result but I have spent lots of minutes in this last effort. Does anyone know the solution?
Thanks in advance.
The Query:
SELECT DISTINCT
candidate_basic.id_candidate_basic,
candidate_lang.town,
province.name,
degree_of_candidate.id_degree_of_candidate,professional_experience_basic.main_job
FROM (((((candidate_basic
INNER JOIN candidate_lang
ON candidate_lang.id_candidate_basic=candidate_basic.id_candidate_basic)
INNER JOIN province_of_candidate
ON province_of_candidate.id_candidate_basic=candidate_basic.id_candidate_basic)
INNER JOIN province
ON province.id_province=province_of_candidate.id_province)
INNER JOIN degree_of_candidate
ON degree_of_candidate.id_candidate_basic=candidate_basic.id_candidate_basic)
LEFT JOIN professional_experience_basic
ON professional_experience_basic.candidate_id=candidate_basic.id_candidate_basic)
WHERE candidate_basic.candidate_state=2
AND degree_of_candidate.is_main_degree
AND candidate_lang.id_website_lang=1
The current result:
The result I want:
Change professional_experience_basic.main_job to max(professional_experience_basic.main_job) in the column list, then:
GROUP BY candidate_basic.id_candidate_basic, candidate_lang.town,
province.name, degree_of_candidate.id_degree_of_candidate
First Group your Result
... AND candidate_lang.id_website_lang=1
GROUP BY
candidate_basic.id_candidate_basic,
candidate_lang.town,
province.name,
degree_of_candidate.id_degree_of_candidate
And i think you want the max of main_job, but i dont know.
change select to:
SELECT DISTINCT
candidate_basic.id_candidate_basic,
candidate_lang.town,
province.name,
degree_of_candidate.id_degree_of_candidate,MAX(professional_experience_basic.main_job)
It seems like you want the max here, but i dont know
Still a mysql newb and I looked extensively through previous questions trying to find an appropriate solution.
I have two tables CaseReportsTempImport2011Q3 and FDADrugsDB, I want to do a left join to match CaseReportsTempImport2011Q3.drugname to FDADrugsDB.ReferenceDrugName and FDADrugsDB.DrugName
What I envisioned was something like:
SELECT DISTINCT(CaseReportsTempImport2011Q3.DRUGNAME)
, FDADrugsDB_Product.drugname
, FDADrugsDB_Product.ReferenceDrug
, FDADrugsDB_Product.activeingred
FROM CaseReportsTempImport2011Q3
LEFT JOIN FDADrugsDB_Product ON CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.ReferenceDrug)
LEFT JOIN FDADrugsDB_Product ON CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.DrugName)
ORDER BY LENGTH(CaseReportsTempImport2011Q3.DRUGNAME) ASC
But that doesn't work I get 'Not unique table/alias: 'FDADrugsDB_Product'' - Any help?
Thanks
EDIT FOR BETTER SOLUTION REQUEST/REPHRASE
Per borealids "However, I'm not sure this is what you want to do - joining the table twice will produce a multiplicative number of results. I think you might have wanted one join with an ON ... OR ..., making the join condition an "or" of the two reasons for linkage."
I would like to know how to do that.
SOLUTION
ON CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.ReferenceDrug) OR CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.DrugName
Thanks tom and borealid.
To make the query you wrote valid, you need to assign two different relation names to the two uses of the same table.
LEFT JOIN FDADrugsDB_Product FDA_first ON
and
LEFT JOIN FDADrugsDB_Product FDA_second ON
and then use the names FDA_first and FDA_second to refer to results from each set distinctly. Otherwise the query engine can't tell what you mean when you say FDADrugsDB_Product - there are two of them, each different!
However, I'm not sure this is what you want to do - joining the table twice will produce a multiplicative number of results. I think you might have wanted one join with an ON ... OR ..., making the join condition an "or" of the two reasons for linkage.
You need to give the tables alias names, otherwise MySql won't know which instance of the FDADrugsDB table you are talking about. i.e.
FROM CaseReportsTempImport2011Q3 a
LEFT JOIN FDADrugsDB_Product b ON CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.ReferenceDrug)
LEFT JOIN FDADrugsDB_Product c ON CaseReportsTempImport2011Q3.DRUGNAME LIKE TRIM(FDADrugsDB_Product.DrugName)
...
FROM
CaseReportsTempImport2011Q3 i
LEFT JOIN FDADrugsDB_Product p ON i.DRUGNAME LIKE TRIM(p.ReferenceDrug)
OR i.DRUGNAME LIKE TRIM(p.DrugName)
ORDER BY
LENGTH(i.DRUGNAME) ASC
Note that you should probably use = instead of LIKE, unless ReferenceDrug and DrugName contain match patterns.