MySQL --- Explicit INNER JOIN with selection from multiple tables - mysql

Whenever I have a need to do an inner join where I have to select columns from multiple tables, I have got the syntax working correctly with implicit joins, without any difficulty. However, I have struggled to get it working with explicit inner joins.
Let me illustrate with an example from the MySQL World Database
My illustrative query, using implicit inner join, is as follows:
SELECT Name, Language, Percentage
FROM Country, CountryLanguage WHERE Code = CountryCode ;
This works as expected. I can have the columns in any order, from either table, without any issues.
I would like to have the explicit INNER JOIN version of the above query (using "INNER JOIN" and "ON").

You can simply replace the , in your implicit join with the word JOIN:
SELECT Name, Language, Percentage
FROM Country
JOIN CountryLanguage
WHERE Code = CountryCode
and the query will work fine. You can also replace WHERE with ON and again it will work fine. Finally if you want to explicitly name the tables where the columns come from (and this is the preferred approach), you would use:
SELECT c.Name, cl.Language, cl.Percentage
FROM Country c
JOIN CountryLanguage cl
ON c.Code = cl.CountryCode

Maybe it would be like
SELECT Name, Language, Percentage,
FROM Country
INNER JOIN CountryLanguage ON Country.Code = CountryLanguage.CountryCode

Related

can I query an SQL database and combine four tables in one go?

I’m studying sql command line, and using command in mysql via terminal. I’m studying INNER JOIN, and I found it easy enough, but I have a doubt that I must solve otherwise cannot manage to pass to other commands.
I have these four tables: departments, employees, employees_projects, projects
These tables have the following content:
departments:
id int
name varchar(60)
employees:
id int
first_name varchar(60)
last_name varchar(60)
salary int
department_id int
employees_projects:
project_id int
employee_id int
projects:
id int
title varchar(60)
start_date date
end_date date
budget int
When I want to use INNER JOIN to join two tables I simply use it this way:
SELECT employees.first_name, employees.last_name, departments.name
FROM employees
INNER JOIN departments ON employees.department_id = departments.id;
When I want to join three tables I use the following:
SELECT employees.first_name, employees.last_name, departments.name, employees_projects.project_id
FROM ( (employees
INNER JOIN departments ON employees.department_id = departments.id)
INNER JOIN employees_projects ON employees.id = employees_projects.employee_id);
Here is my question: As you can see the result of the last line will give me employees.first_name, employees.last_name, departments.name, employees_projects.project_id, this mean I would get the employee’s name, surname, department and id of the project they are working on. Now, considering the tables we have above, I cannot manage to create a one line SQL query that give me as a result employees.first_name, employees.last_name, departments.name, projects.title. This mean one query that would give me employee’s name, surname, department and the project’s name they are working on.
Is it possible to achieve this in one line query?
mysql> Thank you everybody!
EDITING THE POST:
I created the following line:
SELECT employees.first_name, employees.last_name, departments.name, projects.title FROM ( (employees, projects INNER JOIN departments ON employees.department_id = departments.id) INNER JOIN employees_projects ON projects.id = employees_projects.project_id AND employees_projects.employee_id = employees.id);
But unfortunately I'm receiving this error, and it's strange because looks the correct column:
mysql> SELECT employees.first_name, employees.last_name, departments.name, projects.title FROM ( (employees, projects INNER JOIN departments ON employees.department_id = departments.id) INNER JOIN employees_projects ON projects.id = employees_projects.project_id AND employees_projects.employee_id = employees.id);
ERROR 1054 (42S22): Unknown column 'employees.department_id' in 'on clause'
mysql>
You are probably familiar with arithmetic notation. You can make an arithmetic expression with any number of terms:
a + b + c + d
The first term has nothing before it. Each term has a + between it. There really isn't a "main" term, because addition has the algebraic property of commutativity. The expression has the same result as:
c + a + d + b
Or any other ordering of the terms.
In SQL, joins are similar. You can in theory join any number of tables.
<table> INNER JOIN <table> ON <condition>
INNER JOIN <table> ON <condition>
INNER JOIN <table> ON <condition>
And you can keep adding more after that if you need to. (I said in theory because MySQL or any other SQL product is just one implementation of the language and it may have a practical limit. In MySQL's case, the limit is 63 tables per query but that's not the fault of the language, it's just how MySQL's code implements joins.)
FROM is not part of the expression, and it doesn't name any table as the "main" table. Inner join has the property of commutativity, like addition in arithmetic. In fact, MySQL can reorder the tables itself as it runs your query, if it turns out to make the query have better performance.
You tried this join:
FROM ( (employees, projects INNER JOIN departments
ON employees.department_id = departments.id)
INNER JOIN employees_projects
ON projects.id = employees_projects.project_id
AND employees_projects.employee_id = employees.id);
You're mixing two syntax forms, and it causes a problem.
Joins with comma are from 1989, and these still work. But they couldn't do OUTER JOIN and so the syntax was changed in 1992 to have the INNER/OUTER JOIN keywords.
But the problem is that the syntax with the INNER/OUTER JOIN keywords has higher precedence than comma. So it's as if your query were joining projects and departments before the query engine has even acknowledged that employees is part of the query. When it checks the ON condition that references employees, it doesn't know about that table.
This is in fact documented: https://dev.mysql.com/doc/refman/8.0/en/join.html search for "JOIN has higher precedence than the comma operator" near the bottom of the page.
The solution is to use only the 1992 style syntax consistently. I would write it the way #Adamszsz writes the query in the other answer.
Use need something like this :
select emp.first_name,emp.last_name,d.name,p.title , p.id from employees emp
join departments d on d.id = emp.department_id
join employees_projects empp on empp.employee_id = emp.id
join projects p on p.id = empp.project_id

MYSQL server: Write a query to display cars which was not taken on rent

Use Cars and Rentals tables to retrieve records.
CARS(car_id, car_name, car_type)
RENTALS(rental_id, cust_id, car_id, pickup_date, km, fare)
SELECT c.car_id, c.car_name, c.car_type
FROM cars as c, rentals as r
WHERE c.car_id=r.car_id and r.pickup_date=null
ORDER BY c.car_id;
I've tried this but output is NO ROWS SELECTED
I would recommend NOT EXISTS for this query:
select c.*
from cars c
where not exists (select 1 from rentals r where r.car_id = c.car_id);
That said, your query has multiple errors:
The comma in the FROM clause is very last-century. Use JOIN.
= NULL is always going to filter out all rows. Almost all comparisons to NULL return NULL which is treated as "false". The correct comparison is IS NULL, but I don't think that is needed.
You can specify equivalent logic using LEFT JOIN, but I think NOT EXISTS is closer to the statement of the question.
Your original intent was to join the two tables and filters on rows that did not match on the right side of the join. This technique is sometimes called an anti left join.
Your attempt failed because you need a left join rather than an (implicit) inner join, and because you did not properly check for nullity (this requires operator is null).
The left join solution phrases as:
select c.*
from cars c
left join rentals r on r.car_id = c.car_id
where r.car_id is null
order by c.car_id
Note that I check for nullity on column car_id rather than pickup_date - any column that is not nullable can do, however I find the intent clearer when using the joining column.
A simple way to do this is with NOT IN:
SELECT car_id, car_name, car_type
FROM cars
WHERE car_id NOT IN (SELECT car_id FROM rentals)
ORDER BY car_id;

Inverse result of a query in MySQL

I have three tables in MySQL. Staff with fields id, name, surname, telephone, adress, id_work.
Work with fields id, name.
Absence with fields id, name, id_staff.
I have the following query
SELECT COUNT(*)
FROM staff s, work w, absence a
WHERE s.id=a.id_staff
AND s.id_work=w.id
AND w.name='sales manager'
AND a.name='disease'.
The aforementioned query returns the staff which have the post of sales and are ill.
Is there is a way to return the inverse result namely the staff which have the post of sales but are not ill?
I change my where clause with where not exists but did not work
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
One method of solving this uses LEFT JOIN:
SELECT COUNT(*)
FROM staff s JOIN
work w
s.id_work = w.id LEFT JOIN
absence a
ON s.id = a.id_staff AND a.name = 'disease'
WHERE w.name='sales manager' AND a.id_staff IS NULL;
You should also avoid 'CROSS JOIN' except where it is necessary :
SELECT COUNT(*)
FROM staff s
INNER JOIN work w ON s.id_work = w.id
LEFT JOIN absence a ON s.id = a.id_staff
WHERE w.name='sales manager'
AND a.name = 'disease'
AND a.id_staff IS NULL;

Joining on derived column without using subquery

In MySQL I'm trying to join two tables on a derived column, something like this:
SELECT C.country,
IFNULL(C.preferred_city, C.default_city) AS best_city,
PC.postal_code
FROM Countries as C
INNER JOIN PostalCodes AS PC
ON best_city=PC.city
This of course does not work because best_city is outside the scope of the ON clause.
The only solution I could find was using a subquery (or is this considered a derived table? I'm fuzzy on the nomenclature):
SELECT BC.*, PC.postal_code
FROM (
SELECT country, IFNULL(preferred_city, default_city) AS best_city
FROM COUNTRIES
) AS BC
INNER JOIN PostalCodes AS PC
ON BC.best_city=PC.city
which works nicely from the shell. However, I'm trying to implement this as a view and it gives me the error: ERROR 1349: View's SELECT contains a subquery in the FROM clause
How can I rework this to join without using a subquery??
Thanks!
Try something like:
SELECT BC.*, PC.postal_code
FROM COUNTRIES BC
INNER JOIN PostalCodes AS PC
ON PC.city = IFNULL(preferred_city, default_city)

explain the USING command

Take a look...
http://search.mysql.com/search?site=refman-41&q=using&lr=lang_en
The official MySQL site doesn't explain the USING command.
Can you do that please?
USING is a variation of the ON keyword in join syntax. This link explains it in detail. In the example, the query
SELECT C.First_Name, C.Last_Name, O.title
FROM Employee AS C
LEFT JOIN job as O USING (ID);
is identical to
SELECT C.First_Name, C.Last_Name, O.title
FROM Employee AS C
LEFT JOIN job as O ON C.ID = O.ID;
It's used for JOINs:
MySQL: 12.2.8.1. JOIN Syntax
"The USING(column_list) clause names a list of columns that must exist in both tables. If tables a and b both contain columns c1, c2, and c3, the following join compares corresponding columns from the two tables."
It is used in JOINs, I think you can get here some more information about it.