Create a query to determine which sub_genres come from which regions - mysql

SELECT Sub_Genre.sgid, Sub_Genre.sgname, Region.rname
FROM Sub_Genre AS S, Region AS R
JOIN Band_Styles AS bSty ON bSty.sgname=S.sgname
JOIN Band_Origins AS bOri ON bOri.bname=bSty.bname
JOIN Country AS C ON C.cname=bOri.cname
JOIN Region ON R.rname=C.rname
ORDER BY S.sgid;
I am trying to Create a query to determine which sub_genres come from which regions.
I keep getting an Error Code 1054. Unknown column 'Sub_Genre.sgid' in 'field list'

Don't mix explicit and implicit joins. Use standard, explicit joins consistently.
Table region appears twice in the query, first in an implicit join with an alias, and then in a standard join without an alias. This is most likely not what you want.
Columns in the select clause are prefixed with the entire table name, while the table are aliased in the from clause: this is not supported.
This would be a cleaner way to express the logic:
select s.sgid, s.sgname, r.rname
from sub_genre s
join band_styles bsty on bsty.sgname = s.sgname
join band_origins bori on bori.bname = bsty.bname
join country c on c.cname = bori.cname
join region r on r.rname = c.rname
order by s.sgid;
This fixes the syntax problems. Whether this gives the correct results or not is something else: you did not share the structures and data you are working with, so I cannot tell.

Related

Missing Closing Parenthesis error with "USING" Statement MYSQL

I get a Syntax error: missing 'closing parenthesis' when I add a specifier to my USING statement
Here is an example similar to what I am doing:
SELECT * FROM student s JOIN test_result using (s.id) where s.id = 1335;
My actual query is much more complex, I have multiple tables that I want to join and some tables have columns with the same name so when I try to JOIN one of those tables with a third table, I get a Error Code: 1052. Column 's.id' in from clause is ambiguous. When I try to avoid that by specifying which table's id I want to use I get a Syntax error: missing 'closing parenthesis'
The column(s) within the USING() clause do not take aliases - the base idea is that this column should be available in both tables.
This also has the advantage of disambiguating the column, so you don't event need to prefix it with a table alias in the WHERE claus.
Just:
SELECT *
FROM student s
INNER JOIN test_result ts USING (id)
WHERE id = 1335;
The downside is that, if you use that in a multi-join context where several tables have an id column, you don't get to choose from which table id is picked. This can be troublesome in some situations. In that case, you need to switch back to the join ... on ... syntax:
SELECT *
FROM student s
INNER JOIN test_result ts on ts.id = s.id
WHERE id = 1335;
Reading your comment, I think you need an alias based join
SELECT *
FROM student s
JOIN test_result t ON t.id = s.id
where s.id = 1335;

Master Product list from multiple tables with the exact same column names

I’ve got quite a few tables with product information. The columns on each table that I’m pulling from in this particular query have the exact same column names. I’ve been attempting to do it via a UNION ALL but for some reason it is throwing an error saying non-object but all the column names are correct.
I’m using a format that I found online. But obviously something is wrong. There are more tables; however, this is how it starts (with 2). I’d prefer not to have to code each select statement in the union with unique table abbreviations if I don’t have to.
I don’t have to use union if there is a better method.
All tables share data on Product_Categories and Product_Sub_Category.
The only thing unique to each table is id and part_number.
SELECT f.id,f.part_number,f.cat,f.subcat,f.table_name FROM
(
SELECT t.id,t.part_number,psc.name as subcat,c.name as cat, c.table_name FROM Steel_Strapping as t JOIN Product_Sub_Category as psc ON t.subcat = psc.id JOIN Product_Categories as c ON psc.category = c.id ORDER BY c.sort_order,psc.sort_order,t.sort_order
UNION ALL
SELECT t.id,t.part_number,psc.name as subcat,c.name as cat, c.table_name FROM Product as t JOIN Product_Sub_Category as psc ON t.subcat = psc.id JOIN Product_Categories as c ON psc.category = c.id ORDER BY c.sort_order,psc.sort_order,t.sort_order
) f
My end result is one full list of all products sharing column names. Ex: $result[‘part_number’] will pull part numbers from ALL tables listed in union.
I found the solution when playing around with code. I had to add parenthesis (select...) UNION JOIN (select...) inside the parent select statement

I am not understanding MySQL Joins at all. I'm stuck

So I'm trying to learn some MySQL and I have gotten to a point on Joins. It is doing my head in.
I have a few exercises I am trying to work through and getting no where.
The current exercise calls for this:
Use the pre-1994 SQL syntax (i.e. do not use the INNER JOIN syntax) to display the order date, order number and the shipper company name for orders shipped to
Portugal. Sort the output in ascending order of order date.
I currently have typed this:
SELECT OrderDate, OrderID, ShipperID FROM Shippers Orders
WHERE shippers.shipperID = orders.shipperID AND orders.shipcountry = 'Portugal';
But I am getting this error message:
Error Code: 1054. Unknown column 'OrderDate' in 'field list'
What am I doing wrong? Also, what can I provide to help you guys to help me?
OrderDate DOES exist, as you can see here from my screenshot here of 'Select * from Orders'
So I imagine that is similar but with a different join process.
Thank you in advance!
You have to use table name with column names to identify that which column belongs to which table.
SELECT orders.OrderDate, orders.OrderID,shippers.ShipperID FROM Shippers, Orders
WHERE shippers.shipperID = orders.shipperID AND orders.shipcountry = 'Portugal';
Or you can you aliasing that will be easy to write the query.
SELECT b.OrderDate, b.OrderID, a.ShipperID FROM Shippers a, Orders b
WHERE a.shipperID = b.shipperID AND b.shipcountry = 'Portugal';
Hope this will help.
You can use like this.
SELECT o.OrderDate, o.OrderID, s.ShipperID FROM Shippers s, Orders o
WHERE s.shipperID = o.shipperID AND o.shipcountry = 'Portugal';
Use the pre-1994 SQL syntax
Sounds like the training course is taking you the long way around (though the date is wrong; probably should be 1989)!
The lesson here is that doing a relational product operation between two tables (a.k.a. CROSS JOIN to use the 1992 term, which remains outside core Standard SQL) forces you to use SQL's dot qualified references in the form <range variable reference>.<column reference> in order to disambiguate what would otherwise be duplicated column references (e.g. in your case where shipperID appears in both tables).
I guess the ultimate destination is NATURAL JOIN, where the need for range variables is dispensed with entirely!

LEFT JOIN on multiple tables in "FROM" part

I'm unable to find an exact example on stackoverflow, so here is my problem. In MySQL 4.x it works fine, but 5.x seems not to like the following:
SELECT some stuff..
FROM schools, member , applications
LEFT JOIN courses ON courses.id = applications.course_id
LEFT JOIN staff ON staff.id=member.staff_id
This section throws up an error saying "Unknown column 'member.staff_id' in 'on clause'". How do I change this so that 5.x won't complain?
EDIT: I did notice that when using 'ONE' LEFT JOIN, it did matter where the table name was placed in the FROM part, ie it has to be at the end. Not sure this has any relevance to the problem though. This is only an issue with 5.x
According to the official MySQL doco, the precedence of the join operator is higher than that of the , (comma) operator. This will cause your joins to be evaluated without the member table, meaning member is not available in the join. However because the applications table is the last in your series of comma delineated tables, it IS available to the joins. MySQL effectively sees the tables like this: (schools, member, (applications left join courses ... ))
13.2.8.2 JOIN Syntax
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.
The reason you are encountering this error now, whereas you were able to do it before, is (from the same link)
Previously, the comma operator (,) and JOIN both had the same precedence.
To get around this order of operations limitation, you can either rewrite your query using explicit join syntax only, or you can force the grouping of your comma separated tables by surrounding them with parenthesis, which will make MySQL see your tables more like this ( (schools, member, applications) left join courses ... )
SELECT some stuff..
FROM (schools, member , applications)
LEFT JOIN courses ON courses.id = applications.course_id
LEFT JOIN staff ON staff.id=member.staff_id
But i'd still recommend using explicit join syntax.
select some stuff..
from schools
join member
join applications
left join courses on courses.id = applications.course_id
left join staff on staff.id = member.staff_id
Your edit helped. MySQL doesn't seem to like like that you are mixing the old-style comma separated join syntax with the newer ANSI SQL-92 join syntax.
I would rewrite it as
SELECT some stuff..
FROM schools
JOIN member ON (...)
JOIN applications ON (...)
LEFT JOIN courses ON courses.id = applications.course_id
LEFT JOIN staff ON staff.id=member.staff_id
You will probably have to move some conditions up from your WHERE clause.

In what order are MySQL JOINs evaluated?

I have the following query:
SELECT c.*
FROM companies AS c
JOIN users AS u USING(companyid)
JOIN jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123;
I have the following questions:
Is the USING syntax synonymous with ON syntax?
Are these joins evaluated left to right? In other words, does this query say: x = companies JOIN users; y = x JOIN jobs; z = y JOIN useraccounts;
If the answer to question 2 is yes, is it safe to assume that the companies table has companyid, userid and jobid columns?
I don't understand how the WHERE clause can be used to pick rows on the companies table when it is referring to the alias "j"
Any help would be appreciated!
USING (fieldname) is a shorthand way of saying ON table1.fieldname = table2.fieldname.
SQL doesn't define the 'order' in which JOINS are done because it is not the nature of the language. Obviously an order has to be specified in the statement, but an INNER JOIN can be considered commutative: you can list them in any order and you will get the same results.
That said, when constructing a SELECT ... JOIN, particularly one that includes LEFT JOINs, I've found it makes sense to regard the third JOIN as joining the new table to the results of the first JOIN, the fourth JOIN as joining the results of the second JOIN, and so on.
More rarely, the specified order can influence the behaviour of the query optimizer, due to the way it influences the heuristics.
No. The way the query is assembled, it requires that companies and users both have a companyid, jobs has a userid and a jobid and useraccounts has a userid. However, only one of companies or user needs a userid for the JOIN to work.
The WHERE clause is filtering the whole result -- i.e. all JOINed columns -- using a column provided by the jobs table.
I can't answer the bit about the USING syntax. That's weird. I've never seen it before, having always used an ON clause instead.
But what I can tell you is that the order of JOIN operations is determined dynamically by the query optimizer when it constructs its query plan, based on a system of optimization heuristics, some of which are:
Is the JOIN performed on a primary key field? If so, this gets high priority in the query plan.
Is the JOIN performed on a foreign key field? This also gets high priority.
Does an index exist on the joined field? If so, bump the priority.
Is a JOIN operation performed on a field in WHERE clause? Can the WHERE clause expression be evaluated by examining the index (rather than by performing a table scan)? This is a major optimization opportunity, so it gets a major priority bump.
What is the cardinality of the joined column? Columns with high cardinality give the optimizer more opportunities to discriminate against false matches (those that don't satisfy the WHERE clause or the ON clause), so high-cardinality joins are usually processed before low-cardinality joins.
How many actual rows are in the joined table? Joining against a table with only 100 values is going to create less of a data explosion than joining against a table with ten million rows.
Anyhow... the point is... there are a LOT of variables that go into the query execution plan. If you want to see how MySQL optimizes its queries, use the EXPLAIN syntax.
And here's a good article to read:
http://www.informit.com/articles/article.aspx?p=377652
ON EDIT:
To answer your 4th question: You aren't querying the "companies" table. You're querying the joined cross-product of ALL four tables in your FROM and USING clauses.
The "j.jobid" alias is just the fully-qualified name of one of the columns in that joined collection of tables.
In MySQL, it's often interesting to ask the query optimizer what it plans to do, with:
EXPLAIN SELECT [...]
See "7.2.1 Optimizing Queries with EXPLAIN"
Here is a more detailed answer on JOIN precedence. In your case, the JOINs are all commutative. Let's try one where they aren't.
Build schema:
CREATE TABLE users (
name text
);
CREATE TABLE orders (
order_id text,
user_name text
);
CREATE TABLE shipments (
order_id text,
fulfiller text
);
Add data:
INSERT INTO users VALUES ('Bob'), ('Mary');
INSERT INTO orders VALUES ('order1', 'Bob');
INSERT INTO shipments VALUES ('order1', 'Fulfilling Mary');
Run query:
SELECT *
FROM users
LEFT OUTER JOIN orders
ON orders.user_name = users.name
JOIN shipments
ON shipments.order_id = orders.order_id
Result:
Only the Bob row is returned
Analysis:
In this query the LEFT OUTER JOIN was evaluated first and the JOIN was evaluated on the composite result of the LEFT OUTER JOIN.
Second query:
SELECT *
FROM users
LEFT OUTER JOIN (
orders
JOIN shipments
ON shipments.order_id = orders.order_id)
ON orders.user_name = users.name
Result:
One row for Bob (with the fulfillment data) and one row for Mary with NULLs for fulfillment data.
Analysis:
The parenthesis changed the evaluation order.
Further MySQL documentation is at https://dev.mysql.com/doc/refman/5.5/en/nested-join-optimization.html
SEE http://dev.mysql.com/doc/refman/5.0/en/join.html
AND start reading here:
Join Processing Changes in MySQL 5.0.12
Beginning with MySQL 5.0.12, natural joins and joins with USING, including outer join variants, are processed according to the SQL:2003 standard. The goal was to align the syntax and semantics of MySQL with respect to NATURAL JOIN and JOIN ... USING according to SQL:2003. However, these changes in join processing can result in different output columns for some joins. Also, some queries that appeared to work correctly in older versions must be rewritten to comply with the standard.
These changes have five main aspects:
The way that MySQL determines the result columns of NATURAL or USING join operations (and thus the result of the entire FROM clause).
Expansion of SELECT * and SELECT tbl_name.* into a list of selected columns.
Resolution of column names in NATURAL or USING joins.
Transformation of NATURAL or USING joins into JOIN ... ON.
Resolution of column names in the ON condition of a JOIN ... ON.
Im not sure about the ON vs USING part (though this website says they are the same)
As for the ordering question, its entirely implementation (and probably query) specific. MYSQL most likely picks an order when compiling the request. If you do want to enforce a particular order you would have to 'nest' your queries:
SELECT c.*
FROM companies AS c
JOIN (SELECT * FROM users AS u
JOIN (SELECT * FROM jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123)
)
as for part 4: the where clause limits what rows from the jobs table are eligible to be JOINed on. So if there are rows which would join due to the matching userids but don't have the correct jobid then they will be omitted.
1) Using is not exactly the same as on, but it is short hand where both tables have a column with the same name you are joining on... see: http://www.java2s.com/Tutorial/MySQL/0100__Table-Join/ThekeywordUSINGcanbeusedasareplacementfortheONkeywordduringthetableJoins.htm
It is more difficult to read in my opinion, so I'd go spelling out the joins.
3) It is not clear from this query, but I would guess it does not.
2) Assuming you are joining through the other tables (not all directly on companyies) the order in this query does matter... see comparisons below:
Origional:
SELECT c.*
FROM companies AS c
JOIN users AS u USING(companyid)
JOIN jobs AS j USING(userid)
JOIN useraccounts AS us USING(userid)
WHERE j.jobid = 123
What I think it is likely suggesting:
SELECT c.*
FROM companies AS c
JOIN users AS u on u.companyid = c.companyid
JOIN jobs AS j on j.userid = u.userid
JOIN useraccounts AS us on us.userid = u.userid
WHERE j.jobid = 123
You could switch you lines joining jobs & usersaccounts here.
What it would look like if everything joined on company:
SELECT c.*
FROM companies AS c
JOIN users AS u on u.companyid = c.companyid
JOIN jobs AS j on j.userid = c.userid
JOIN useraccounts AS us on us.userid = c.userid
WHERE j.jobid = 123
This doesn't really make logical sense... unless each user has their own company.
4.) The magic of sql is that you can only show certain columns but all of them are their for sorting and filtering...
if you returned
SELECT c.*, j.jobid....
you could clearly see what it was filtering on, but the database server doesn't care if you output a row or not for filtering.