How can I join 4 tables using SQL to get a result - mysql

Here is a simple database schema, according to the schema, I would like to find the highest salary among all employees, presenting the information about that employee (a_id, a_name, b_area).
There will be only one result return from table D and I try to return the employment_id to link with other tables but then it returns more than 1 result. Please check my query underneath, thank you very much :)
SELECT
a.a_id,
a.a_name,
b.b_area
FROM
A a, B b, C c
LEFT JOIN (SELECT d.employee_id, MAX(d.salary) FROM D d)
ON d.employee_id= c.employee_id;

Start with D, then join the other tables as needed:
... D left join c on (d.employee_id = c.employee_id) left join a on ...
And the highest salary bit would be something like:
... where salary = (select max(salary) from d)
Keep in mind that this will return multiple results if there is more than one employee having the maximum salary.

You miss a join condition for your tables. This should do what you need.
SELECT a.a_id, a.a_name, b.b_area
FROM C
JOIN A ON a.a_id = c.a_id
JOIN B ON b.b_id = c.c_id
JOIN D ON d.employee_id = c.employee_id
WHERE d.salary = (SELECT max(salary) FROM D)

SELECT D.*, a.a_name, b.b_area FROM D
LEFT JOIN c ON d.employee_id = c.employee_id
LEFT JOIN a ON a.a_id = c.a_id
LEFT JOIN b ON b.b_id = c.a_id
ORDER BY D.salary DESC LIMIT 1
This will output one row as:
employee_id | salary | a_name | b_area

There are several ways:
Subselect-Solution:
SELECT A.a_name
,B.b_area
,maxsalary.MaxSal
FROM
(
SELECT D.employee_id
,MAX(D.Salary) as MaxSal
FROM D
GROUP BY D.employee
) maxsalary
INNER JOIN C
ON C.employee_id = maxsalary.employee_id
INNER JOIN B
ON C.b_id = B.b_id
INNER JOIN A
ON C.a_id = A.a_id
This solution might be more performant. As SUBSELECT maxsalary will return just one row.

I think you use HAVING Clause,
SELECT a.a_id, a.a_name, b.b_area FROM A a, B b, C c LEFT JOIN D d ON c.employee_id = d.employee_id
GROUP BY d.salary
HAVING MAX(d.salary);

Related

SELECT JOIN with conditional (OR) cross

I need to do something like this (in MySQL), my attempts using UNION won't work until now.
In theory:
SELECT * FROM
tableA A
JOIN tableB B ON A.tableAId = B.tableAId
LEFT JOIN tableC C ON C.tableAId = A.tableAId
LEFT JOIN tableD D ON D.tableAId = A.tableAId
JOIN tableE E
ON (C.tableEId = E.tableEId OR D.tableEId = E.tableEId)
The expected result is crossing A with B, optional C with A, optional D with A and get the E result if its id is on C or D.
In order to know if the record found is from C or D, I'm using an IF checking if tableCId or tableDId are null.
I think your code will work.
SELECT *
FROM tableA A JOIN
tableB B
ON A.tableAId = B.tableAId LEFT JOIN
tableC C
ON C.tableAId = A.tableAId LEFT JOIN
tableD D
ON D.tableAId = A.tableAId JOIN
tableE E
ON E.tableEId IN (C.tableEId, D.tableEId);
This will filter out rows that have no matches in C and D, as well as those whose matches in C/D are not in E. I assume that is desirable.
Also, OR and IN can have a bad impact on JOIN performance, but you don't mention performance as a concern.

Why am I getting duplicates in a join between four tables?

tables and query are here
http://sqlfiddle.com/#!9/2b6f35a/1/0
In it for each name i get its tags title, So it would be like this
name1: title1;
name2: title1;
name3: title1;
My problem is that i get double the tags
name1: title1, title1;
name2: title1, title1;
name3: title1;
What is the mistake i've made?
The entire problem comes for tablx
Sorry about the mess before, didn't know about sqlfiddle
The join with X table is returning the 4th row. http://sqlfiddle.com/#!9/2b6f35a/6, which draws the same title1 value in from the tags table, which is then aggregated into the final response with GROUP_CONCAT()
A solution if you need to join both these tables in one query but only want the title1 one time is to remove the GROUP_CONCAT() aggregator: http://sqlfiddle.com/#!9/2b6f35a/7
SELECT a.name, x.rate, c.title
FROM tabl1 a
LEFT JOIN tablx x ON x.pid = a.id
INNER JOIN tabl2 b ON a.id = b.pid
INNER JOIN tabl3 c ON c.id = b.bid
WHERE c.title IN ('title1')
GROUP BY a.id
In your case, it might be more useful to have an aggregator on the rate column for x table, like so: http://sqlfiddle.com/#!9/2b6f35a/9
SELECT a.name, x.rate, c.title, SUM(x.rate) AS rate_sum
FROM tabl1 a
LEFT JOIN tablx x ON x.pid = a.id
INNER JOIN tabl2 b ON a.id = b.pid
INNER JOIN tabl3 c ON c.id = b.bid
WHERE c.title IN ('title1')
GROUP BY a.id
If you just want to count the number of distinct tags in this situation, you can use COUNT(DISTINCT...). http://sqlfiddle.com/#!9/2b6f35a/15:
SELECT a.name, b.id as bid, c.title, x.id as xid, x.rate, c.title, SUM(x.rate) AS rate_sum, COUNT(DISTINCT c.title) as title_count
FROM tabl1 a
LEFT JOIN tablx x ON x.pid = a.id
INNER JOIN tabl2 b ON a.id = b.pid
INNER JOIN tabl3 c ON c.id = b.bid
WHERE c.title IN ('title1')
GROUP BY a.id
If everything in the posted question is correct, you aren't doing anything wrong.
See this sqlfiddle:
http://sqlfiddle.com/#!9/03205d/1

Incorrect id returned on LEFT JOIN in Mysql statement

I need to get the id and timestamps of table sellers and all other columns (without knowing the column names) from these results returned from this MySql statement:
SELECT * FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
The seller id though is incorrectly set because users, country_types, and language_types all have a value id. How can I set seller_id and seller_timestamp? I tried this but it is incorrect:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a ...
You want this:
SELECT a.id as seller_id, a.timestamp as seller_timestamp, a.*, b.*, c.*, d.*
FROM sellers a
LEFT JOIN users b ON a.user_id = b.id
LEFT JOIN country_types c ON a.country_type_id = c.id
LEFT JOIN language_types d ON a.language_type_id = d.id
WHERE a.email=?
Im not sure but try alias, for example:
a.id AS seller_id
and etc.
In joins you can't select other columns in this way:
SELECT a.id seller_id, a.timestamp seller_timestamp, * FROM sellers a...
You need to write required column names.

Mysql inner join twice and use WHERE on both joins

In MySQL, I want to SELECT A.* FROM A where an inner join condition is satisfied whether directly (joining table B) or through another join table (C), WHERE B.field = myvalue. Can anyone point out the proper way to get results?
I have the following tables: A, B, C, which are associated as follows (A joins B, B joins C, A joins C):
B
/ \
A --- C
It looks pretty straightforward, but I get an empty set when I run the following code, even though I get results when I restrict the search to just joining B through C:
SELECT A.* FROM A
INNER JOIN C ON C.id = A.c_id
INNER JOIN B AS B_thru_C ON B_thru_C.id = C.b_id
INNER JOIN B AS B_from_A ON B_from_A.id = A.b_id
WHERE B_thru_C.field = 'myvalue' OR B_from_A.field = 'myvalue';
# yields an empty set
SELECT A.* FROM A
INNER JOIN C ON C.id = A.c_id
INNER JOIN B AS B_thru_C ON B_thru_C.id = C.b_id
WHERE B_thru_C.field = 'myvalue';
# yields results
How about this?
SELECT A.* FROM A
LEFT OUTER JOIN C ON C.id = A.c_id
INNER JOIN B ON B.id = A.b_id OR B.id = C.b_id
WHERE B.field = 'myvalue';

MySQL Question (joins)

I'm not that into MySQL joins, so maybe you could give me a hand. I've got the following tables:
Table a
Fields ID,name
Table b
Fields aID,cID,ID,found
Table c
Fields ID,name
The result I want to get is the following: I want all the records where b.found = 1. Of these records I don't want a.id or a.name, but I want the number of records that would have been returned if I would have wanted so. So if there are five records that have b.found = 1 and c.id = (for example) 3, then I want a returned value of 5, c.id and c.name.
Someone is able to do this?
Actually this is what I want to get from the database:
A list of all records in table C and a count of records in table B that has found = 1 and b.c_id = c.id
Table: a
Fields: ID, name
Table: b
Fields: aID, cID, found
Table: c
Fields: ID, name
SELECT c.ID, c.name, COUNT(1)
FROM b
JOIN c ON c.ID = b.cID AND b.found=1
GROUP BY c.ID
SELECT c.id, c.name, COUNT(*)
FROM c
INNER JOIN b
ON c.id = b.c_id
AND b.found = 1
GROUP BY c.id, c.name
SELECT COUNT(*), c.id, c.name
FROM a, b, c
WHERE a.id = b.a.id AND c.id = b.a.id AND b.found = 1 AND c.id = idThatIAmSearchingFor
Apologies if I didn't get the syntax exact, but I believe that's the basic structure you want. The COUNT function returns the number of rows found by the query.
Something like:
SELECT count(`c`.*),
`c`.`id`,
`c`.`name`
FROM `b`
JOIN `c`
ON `c`.`id` = `b`.`c_id`
WHERE `b.found` = 1
I think this would provide the required output -
select count(*), b.cID, c.name from b
inner join c on c.id=b.cID and b.found=1
group by b.cID
SELECT COUNT(*) AS Count, c.id, c.name
FROM b join a on a.id = b.a_id
WHERE b.found = 1
GROUP BY c.Id;
COUNT returns count of records in each group from GROUP BY.