I have three tables
I would like to request all persons, where the companyTypeID is for example '2'. How can I query that?
You could use the in operator:
SELECT *
FROM persons
WHERE CompanyId IN (SELECT CompanyId
FROM company
WHERE CompanyTypeId = 2)
Do an INNER JOIN (left or right joins are functionally similar, the only difference is which side of the equation is honoured). Nested queries / subqueries are extremely expensive if they become dependent in nature—even though that's not the scenario in your case—and I do not recommend using them for large tables.
SELECT t1.*
FROM Persons AS t1
LEFT JOIN Company AS t2 ON
t2.companyTypeID = t1.CompanyID
To ensure that you are using an index for joining, you should create indexes on the companyTypeID and CompanyID columns of each table. Prepend EXPLAIN EXTENDED to the query above to verify that the indexes are indeed being used.
You need to use SQL statement JOIN. It's all about mathematical sets!
A Graphic (and superficial) explanation about JOINs statement under mathematical sets approach:
https://www.google.com.br/imgres?imgurl=http%3A%2F%2Fi.imgur.com%2FhhRDO4d.png&imgrefurl=https%3A%2F%2Fwww.reddit.com%2Fr%2Fprogramming%2Fcomments%2F1xlqeu%2Fsql_joins_explained_xpost_rsql%2F&docid=q4Ank7XVw8j7DM&tbnid=f-L_7a3HkxW_3M%3A&w=1000&h=740&client=ubuntu&bih=878&biw=1745&ved=0ahUKEwj2oaer5evPAhUBFZAKHe4nAdAQMwgdKAEwAQ&iact=mrc&uact=8#h=740&w=1000
SQL for your problem(If I got this):
SELECT * FROM Persons p LEFT JOIN Company c ON c.ID = p.companyID
LEFT JOIN CompanyType ct ON ct.ID = c.companyTypeID
WHERE c.id = 2;
Why 'LEFT JOIN'? Checkout the the link about set approach explanation above!
The second 'LEFT JOIN' is just to bring the description of companyType table.
The "*" in statement is didatic! You must not use this in production for the good of performance. Therefore, you must to replace the '*' with all the fields you need. For example, "CONCAT(p.firstname,CONCAT(" ",p.lastname)) as PersonName, c.name CompanyName,..." or something like that. I suppose you're using MySQL
Hope I've helped!
Perform an SQL join:
Joins are quicker than the subquery, in the other post:
SELECT Persons.firstname AS first name
FROM Persons
JOIN Company ON company.ID == Persons.CompanyID
WHERE Company.companyTypeID == 2
Although you will need to select all he fields you want, using alias to simplify the names
Related
I am pretty new to SQL. Here is an operation I am sure is simple for a lot of you. I am trying to join two tables across databases on the same server – dbB and dbA, and TableA (with IdA) and TableB (with IdB) respectively. But before doing that I want to transform column IdA into a number, where I would like to remove the “:XYZ” character from its values and add a where statement for another column in dbA too. Below I show my code for the join but I am not sure how to convert the values of the column. This allows me to match idAwith idB in the join. Thanks a ton in advance.
Select replace(idA, “:XYZ”, "")
from dbA.TableA guid
where event like “%2015”
left join dbB.TableB own
on guid.idA = own.idB
Few things
FROM, Joins, WHERE (unless you use subqueries) syntax order it's also the order of execution (notice select isn't listed as its near the end in order of operation but first syntactically!)
alias/fully qualify columns when multiple tables are involved so we know what field comes from what table.
order of operations has the SQL doing the from and JOINS 1st thus what you do in the select isn't available (not in scope yet) for the compiler, this is why you can't use select column aliases in the from, where or even group by as well.
I don't like Select * usually but as I don't know what columns you really need... I used it here.
As far as where before the join. most SQL compilers anymore use cost based optimization and figure out the best execution plan given your data tables and what not involved. So just put the limiting criteria in the where in this case since it's limiting the left table of the left join. If you needed to limit data on the right table of a left join, you'd put the limit on the join criteria; thus allowing it to filter as it joins.
probably need to cast IDA as integer (or to the same type as IDB) I used trim to eliminate spaces but if there are other non-display characters, you'd have issues with the left join matching)
.
SELECT guild.*, own.*
FROM dbA.TableA guid
LEFT JOIN dbB.TableB own
on cast(trim(replace(guid.idA, ':XYZ', '')) as int) = own.idB
WHERE guid.event like '%2015'
Or materialize the transformation first by using a subquery so IDA in its transformed state before the join (like algebra ()'s matter and get processed inside out)
SELECT *
FROM (SELECT cast(trim(replace(guid.idA, ':XYZ', '')) as int) as idA
FROM dbA.TableA guid
WHERE guid.event like '%2015') B
LEFT JOIN dbB.TableB own
on B.IDA = own.idB
I have two tables: finaldata and finalqualification, and finlpcqlfctin_qlifictins_id is the foreign key in finaldata i.e. is a primary key in finalqualification table.
I want to get all the data from these two tables through a subquery in MYSQL , but it is showing me an error. My query is:
SELECT result.name FROM (SELECT * FROM finalpocpassportdata f LEFT JOIN finalpocqualification q ON f.id=q.id)result
Quick Hint here - if your sub query returns more than one column with the same name it will fall over. We strongly GUID all our data with consistent field names, eg. customerGUID, so I come across this quite regular. Especially when you are using sub queries with joins.
Your subquery return more than value
SELECT result.name FROM (SELECT * FROM finaldata f LEFT JOIN finalqualification ON f.id=f.finlpcqlfctin_qlifictins_id)
you need to specify the name of column also you have a problem in your alias
SELECT result.name FROM (SELECT only_one_column FROM finaldata f LEFT JOIN finalqualification ON f.id=finalqualification .finlpcqlfctin_qlifictins_id)
This is your query:
SELECT result.name
FROM (SELECT *
FROM finalpocpassportdata f LEFT JOIN
finalpocqualification q
ON f.id = q.id
) result;
Obviously, this is a test query, because the subquery is unnecessary and adversely affects performance.
Equally obvious, the SELECT * has two columns with the name id. It might have other columns with the same name as well. But, if id are the only duplicates, then one simple solution is to use USING:
SELECT result.name
FROM (SELECT *
FROM finalpocpassportdata f LEFT JOIN
finalpocqualification q
USING (id)
) result;
(Although NATURAL JOIN is also an option, I strongly advise not to use it here or anywhere. It is just bugs waiting to happen.)
If there are other columns with the same name -- which can happen for very reasonable purposes -- then you can list the columns individually. That is sometimes a pain, it can be easier to use * for one table and list from another:
SELECT . . .
FROM (SELECT f.*, q.name
. . .
In practice, I cannot see a need for this sort of subquery. There is little need to do a join as a subquery, because you can have many joins in a single FROM clause.
I don't think so to get name you need subquery
SELECT name FROM finalpocpassportdata f LEFT JOIN
finalpocqualification q ON f.id=q.id
This query will also give the same result.
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 would like to use join instead of inline queries but the one I was able to make is giving wrong values.
Please check this link - http://www.sqlfiddle.com/#!2/57cad/9
It has 2 individual queries which give correct values and a join query which gives an incorrect result.
Can someone please help...
Answer shown here: SQLFiddle
Your queries could be improved upon in a few areas which make their JOINing a little more obvious.
In your first query, a better version has the the GROUP BY clause's columns listed in the SELECT clause and your HAVING clause (while working) becomes the WHERE clause (IMO: The best practice is to use aggregate function only in the HAVING clause:)
SELECT usercode, ROUND(coalesce(sum(paymentamount)*0.99,0),2) AS payment
FROM accountpayments
WHERE usercode = 21
GROUP BY usercode;
Your second query can be rewritten as a JOIN (vs. the subquery)
SELECT campaigns.usercode, ROUND(coalesce(sum(lmc_cds.total_spending),0),2) AS total_spending
FROM logsmaincontrols_campaigns_daily_stats AS lmc_cds
JOIN campaigns
ON campaigns.campcode = lmc_cds.campcode
WHERE campaigns.usercode = 21;
Since the queries don't share any tables, I decided to JOIN the queries to each other as derived tables using the usercode as the JOINing column.
SELECT t1.usercode, t1.payment, t2.total_spending
FROM (SELECT usercode, ROUND(coalesce(sum(paymentamount)*0.99,0),2) AS payment
FROM accountpayments
WHERE usercode = 21
GROUP BY usercode) AS t1
JOIN (SELECT campaigns.usercode, ROUND(coalesce(sum(lmc_cds.total_spending),0),2) AS total_spending
FROM logsmaincontrols_campaigns_daily_stats AS lmc_cds
JOIN campaigns
ON campaigns.campcode = lmc_cds.campcode
WHERE campaigns.usercode = 21) AS t2
ON t1.usercode = t2.usercode;
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.