How to make Group By With multi inner join - mysql

i try to make filttering for selected data using inner join
i have 3 tables i should join it
this is my query
SELECT DISTINCT *
FROM products_products
INNER JOIN products_products_translations on products_products.id = products_products_translations.entry_id
INNER JOIN products_products_related on products_products.id = products_products_related.entry_id
INNER JOIN upload_files on products_products_related.related_id = upload_files.related_id
WHERE products_products_translations.locale = 'tr'
GROUP BY products_products_related.entry_id;
And this is the error that i got
Query 1 ERROR: Expression #35 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'shop.products_products_translations.id' which is not functionally
dependent on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by

Remove the distinct, and add products_products_related.entry_id, COUNT(*)
SELECT products_products_related.entry_id, COUNT(*)
FROM products_products
INNER JOIN products_products_translations on products_products.id = products_products_translations.entry_id
INNER JOIN products_products_related on products_products.id = products_products_related.entry_id
INNER JOIN upload_files on products_products_related.related_id = upload_files.related_id
WHERE products_products_translations.locale = 'tr'
GROUP BY products_products_related.entry_id;

You can't directly select the columns that are not coming after the group by clause.
The reason is when you group by any column, entry_id for example, you'll have single row for each entry_id. But, each entry_id has many rows in the original table with many different values in the other columns.
Therefore, you need to tell the query how to aggregate the columns which are not the columns you decided to group by.
You can aggregate them by COUNT(...) or SUM(...), or many other functions.
The solution would be something like the following:
SELECT products_products_related.entry_id, MAX(Column1), MIN(Column2) /*etc...*/
FROM products_products
INNER JOIN products_products_translations on products_products.id = products_products_translations.entry_id
INNER JOIN products_products_related on products_products.id = products_products_related.entry_id
INNER JOIN upload_files on products_products_related.related_id = upload_files.related_id
WHERE products_products_translations.locale = 'tr'
GROUP BY products_products_related.entry_id;

Related

SQL Complex update query filter distinct values only

I have 3 tables with following columns.
Table: A with column: newColumnTyp1, typ2
Table: B with column: typ2, tableC_id_fk
Table: C with column: id, typ1
I wanted to update values in A.newColumnTyp1 from C.typ1 by following logic:
if A.typ2=B.typ2 and B.tableC_id_fk=C.id
the values must be distinct, if any of the conditions above gives multiple results then should be ignored. For example A.typ2=B.typ2 may give multiple result in that case it should be ignored.
edit:
the values must be distinct, if any of the conditions above gives multiple results then take only one value and ignore rest. For example A.typ2=B.typ2 may give multiple result in that case just take any one value and ignore rest because all the results from A.typ2=B.typ2 will have same B.tableC_id_fk.
I have tried:
SELECT DISTINCT C.typ1, B.typ2
FROM C
LEFT JOIN B ON C.id = B.tableC_id_fk
LEFT JOIN A ON B.typ2= A.typ2
it gives me a result of table with two columns typ1,typ2
My logic was, I will then filter this new table and compare the type2 value with A.typ2 and update A.newColumnTyp1
I thought of something like this but was a failure:
update A set newColumnTyp1= (
SELECT C.typ1 from
SELECT DISTINCT C.typ1, B.typ2
FROM C
LEFT JOIN B ON C.id = B.tableC_id_fk
LEFT JOIN A ON B.typ2= A.type2
where A.typ2=B.typ2);
I am thinking of an updateable CTE and window functions:
with cte as (
select a.newColumnTyp1, c.typ1, count(*) over(partition by a.typ2) cnt
from a
inner join b on b.type2 = a.typ2
inner join c on c.id = b.tableC_id_fk
)
update cte
set newColumnTyp1 = typ1
where cnt > 1
Update: if the columns have the same name, then alias one of them:
with cte as (
select a.typ1, c.typ1 typ1c, count(*) over(partition by a.typ2) cnt
from a
inner join b on b.type2 = a.typ2
inner join c on c.id = b.tableC_id_fk
)
update cte
set typ1 = typ1c
where cnt > 1
I think I would approach this as:
update a
set newColumnTyp1 = bc.min_typ1
from (select b.typ2, min(c.typ1) as min_typ1, max(c.typ1) as max_typ1
from b join
c
on b.tableC_id_fk = c.id
group by b.type2
) bc
where bc.typ2 = a.typ2 and
bc.min_typ1 = bc.max_typ1;
The subquery determines whether typ1 is always the same. If so, it is used for updating.
I should note that you might want the most common value assigned, instead of requiring unanimity. If that is what you want, then you can ask another question.

How can I grab all rows from one table, but filter the second table?

I am running a query on a PHP page that will pull all records from one table, INNER JOIN with two other tables and then list all of the results. However on the second table I only want the most recent record.
Here is my query
SELECT * FROM wn_trailer
INNER JOIN (
SELECT id, trailer_id, trailer_status, trailer_assigned, MAX(last_update), trailer_lat, trailer_long
FROM wn_trailer_history
) AS th ON wn_trailer.id = th.trailer_id
INNER JOIN wn_trailer_status ON wn_trailer_status.id = th.trailer_status
INNER JOIN wn_users ON wn_users.id = th.trailer_assigned
ORDER BY trailer_number ASC
The query runs but returns only the first record.
You want an additional JOIN to bring in the data on the last update date. Also, your subquery needs a GROUP BY:
SELECT *
FROM wn_trailer t INNER JOIN
(SELECT trailer_id, MAX(last_update) as max_last_update
FROM wn_trailer_history
GROUP BY trailer_id
) tht
ON t.id = tht.trailer_id INNER JOIN
wn_trailer_history th
ON th.trailer_id = tht.trailer_id AND
th.last_update = tht.max_last_update INNER JOIN
wn_trailer_status ts
ON ts.id = th.trailer_status INNER JOIN
wn_users u
ON u.id = th.trailer_assigned
ORDER BY trailer_number ASC;
I also added table aliases so the query is easier to write and to read.

How to access parent column from a subquery within a join

I'm trying to left join the second table useri_ban based on the users' ids, with the extra condition: useri_ban.start_ban = max_start.
In order for me to calculate max_start, I have to run the following subquery:
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id)
Furthermore, in order to add max_start to every row, I need to inner join this subquery's result into the main result. However, it seems that once I apply that join, the subquery is no longer able to access useri.id.
What am I doing wrong?
SELECT
useri.id as id,
useri.email as email,
useri_ban.warning_type_id as warning_type_id,
useri_ban.type as type,
useri.created_at AS created_at
FROM `useri`
inner join
(SELECT MAX(ub.start_ban) AS max_start, user_id FROM useri_ban ub WHERE ub.user_id = useri.id) `temp`
on `useri`.`id` = `temp`.`user_id`
left join `useri_ban` on `useri_ban`.`user_id` = `useri`.`id` and `useri_ban`.`start_ban` = `max_start`
Does this solve your problem? You need GROUP BY in the inner query instead of another join.
SELECT useri.id, useri.email, maxQuery.maxStartBan
FROM useri
INNER JOIN
(
SELECT useri_ban.user_id ubid, MAX(useri_ban.startban) maxStartBan
FROM useri_ban
GROUP BY useri_ban.user_id
) AS maxQuery
ON maxQuery.ubid = useri.id;

count associate rows in multiple tables with left join

I'm trying to select Posts with the associate numbers of Comments and Likes.
This is my query
SELECT `waller_posts`.*,
COUNT(waller_comments.id) AS num_comments,
COUNT(waller_likes.id) AS num_likes
FROM `waller_posts`
LEFT JOIN `waller_comments` ON `waller_comments`.`post_id` = `waller_posts`.`id`
LEFT JOIN `waller_likes` ON `waller_likes`.`post_id` = `waller_posts`.`id`
WHERE `wall_id` = 1
AND `wall_type` = "User"
GROUP BY `waller_posts`.`id`
When I add the second left join in this case of the likes, the results of the num_comments and num_likes came wrong. How can I perform this kind of query?
The query builds up to give you every possible combination of comments and likes on a post.
Probably easiest to just use COUNT(DISTINCT...) :-
SELECT `waller_posts`.*,
COUNT(DISTINCT waller_comments.id) AS num_comments,
COUNT(DISTINCT waller_likes.id) AS num_likes
FROM `waller_posts`
LEFT JOIN `waller_comments` ON `waller_comments`.`post_id` = `waller_posts`.`id`
LEFT JOIN `waller_likes` ON `waller_likes`.`post_id` = `waller_posts`.`id`
WHERE `wall_id` = 1
AND `wall_type` = "User"
GROUP BY `waller_posts`.`id`
Note that your query is relying on a feature of MySQL but which would cause an error in most flavours of SQL. For most flavours of SQL you need to list ALL the non aggregate columns in the GROUP BY clause.
Use Distinct clause because it will display combination of like and comment table data
SELECT `waller_posts`.*,
COUNT(DISTINCT waller_comments.id) AS num_comments,
COUNT(DISTINCT waller_likes.id) AS num_likes
FROM `waller_posts`
LEFT JOIN `waller_comments` ON `waller_comments`.`post_id` = `waller_posts`.`id`
LEFT JOIN `waller_likes` ON `waller_likes`.`post_id` = `waller_posts`.`id`
WHERE `wall_id` = 1
AND `wall_type` = "User"
GROUP BY `waller_posts`.`id`

How Can I use combination of inner join and order by

How Can I use combination of inner join and order by.
My query is running but my output is not giving me the correct answer, im having problem with this line, how can I sort 1 column or the column cm_status only:
INNER JOIN dbfeedersystem.tblrepair on
tblpm.control_number_pm=tblrepair.control_number
SELECT tblfeeder.control_number AS Control_No,tblfeeder.serial_number AS
Serial_No,tblfeeder.model AS Model,
DATE_FORMAT(date_updated_pm,'%d-%b-%Y') AS PM_Date,
DATE_FORMAT(DATE_SUB(due_date,INTERVAL 1 WEEK),'%d-%b-%Y') AS Issuance_of_Recall,
DATE_FORMAT(due_date,'%d-%b-%Y') AS Due_Date, pm_status, cm_status
FROM dbfeedersystem.tblpm INNER JOIN dbfeedersystem.tblrepair on
tblpm.control_number_pm=tblrepair.control_number
INNER JOIN
dbfeedersystem.tblfeeder on
tblpm.control_number_pm=tblfeeder.control_number
INNER JOIN
(SELECT control_number_pm,max(date_updated_pm) AS date_updated_pm FROM
dbfeedersystem.tblpm GROUP BY control_number_pm)
AS MAX USING (control_number_pm,date_updated_pm)
ORDER BY date_updated_pm,control_number_pm;