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

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

Related

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

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);

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` multiples of the same table

Is it possible to INNER JOIN a MySQL query to achieve this result?
I have a table with Strategies and a table with Members. The Strategy table holds the ID of the author that corresponds to their ID in the Member table and the ID of an author that updated the existing author's work. Is it possible to grab a reference to both of these people at the same time? Something like the following, which returns no errors, but also no results...
SELECT * FROM Strategies
INNER JOIN Members AS a
INNER JOIN Members AS b
WHERE Strategies.ID='2'
AND Strategies.AuthorID = a.ID
AND Strategies.UpdateAuthorID = b.ID
Use a LEFT JOIN:
SELECT
s.*,
a.Name AS MemberName,
b.Name AS UpdatedMemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2 ;
If you want them in one column use COALESCE:
SELECT
s.*,
COALESCE(a.Name, b.Name) AS MemberName
FROM Strategies AS s
LEFT JOIN Members AS a ON s.AuthorID = a.ID AND s.ID = 2
LEFT JOIN Members AS b ON s.UpdateAuthorID = b.ID AND s.ID = 2
SELECT toD.dom_url AS ToURL,
fromD.dom_url AS FromUrl,
rvw.*
FROM reviews AS rvw
LEFT JOIN domain AS toD
ON toD.Dom_ID = rvw.rev_dom_for
LEFT JOIN domain AS fromD
ON fromD.Dom_ID = rvw.rev_dom_from
if domain is table name

Optimizing this SQL Query

How would you optimize the following query?
'example_companies' contains companies data.
'example_roles_companies' contains companies roles (pivot)
'example_industries_companies' contains companies industries (pivot)
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b
ON a.contact_id = b.id
LEFT JOIN example_roles_companies c
ON a.id = c.company_id
WHERE "2" IN (SELECT industry_id
FROM example_industries_companies
WHERE company_id = a.id)
AND c.role_id = 2
AND a.account_mode != 2
ORDER BY a.id
Query:
SELECT DISTINCT a.id,
a.mode,
a.name,
a.city,
b.name AS USER,
b.phone
FROM example_companies a
LEFT JOIN example_users b ON a.contact_id = b.id
INNER JOIN example_roles_companies c ON a.id = c.company_id AND c.role_id = 2
INNER JOIN example_industries_companies i
ON i.company_id = a.id AND i.industry_id = "2"
WHERE
a.account_mode != 2
ORDER BY
a.id
Structure:
Index on a.id, not null
Index on b.id, not null [analyze the opportunity of adding another index (b.id, b.name, b.phone) to this table as well]
Index on (c.company_id, c.role_id) not null both
Index on (i.company_id, i.industry_id), not null both
Remarks:
Please note that your industry_id = "2" seems weird to me, ids are generally numbers and if they are not then it should be looked since integers are faster to process than strings. Additionally, this way of double-quoting is not usual in mysql. Are you sure of your syntax?

MySQL GROUP BY performance issue

This is the query I'm performing (without some Joins that are not relevant):
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
GROUP BY a.id
Each row of "a" is linked with 1 to 5 rows in "b".
The problem is that GROUP BY has performance issues (it takes 10x or more using GROUP BY than not using it). I need to retrieve only one row of each member in "a".
How can I make this faster?
edit: I need to be able to filter by a.id AND/OR c.id. The resultset I should be getting is only 1 row per "valid" member of "a", meaning the rows that match the constraints. Rows that don't match the filters shouldn't be returned.
In my original query, this would be done this way:
SELECT a.*, c.id
FROM a
LEFT OUTER JOIN b ON a.id = b.id_anunciante
LEFT OUTER JOIN c ON c.id = b.id_rubro
WHERE c.id = 1
OR a.id = 1
GROUP BY a.id
a.id, b.id_anunciante, b.id_rubro, c.id are all indexes.
SELECT a.*,
(
SELECT c.id
FROM b
JOIN с
ON c.id = b.id_rubro
WHERE b.id_anunciante = a.id
-- add the ORDER BY condition to define which row will be selected.
LIMIT 1
)
FROM a
Create the index on b (id_anunciante) for this to work faster.
Update:
You don't need the OUTER JOINs here.
Rewrite your query as this:
SELECT a.*, c.id
FROM a
JOIN b
ON b.id_anunciante = a.id
JOIN c
ON c.id = b.id_rubro
WHERE a.id = 1
UNION ALL
SELECT a.*, 1
FROM a
WHERE EXISTS
(
SELECT NULL
FROM c
JOIN b
ON b.id_rubro = c.id
WHERE c.id = 1
AND b.id_anunciante = a.id
)
Add ORDER BY NULL to avoid the implicit sorting MySQL does when doing a group by.
I suppose you have indexes/PKs on a.id, b.id_anunciante, b.id_rubro and c.id ? I guess you could try adding a composite index on (b.id_anunciante, b.id_rubro) if your mysql version is not able to do an index merge.