MySQL SELECT with LEFT JOIN & SUM GROUP BY - mysql

Need some help with mysql select with left join, i tried alot of options, looked up for the answers on stack, but can't solve this problem. I'll be grateful for any help. Thanks.
SELECT profile_main.id,
profile_main.add_date,
profile_main.expire_date,
profile_main.status_begin,
profile_main.status_expire,
profile_main.views,
profile_main.last,
profile_main.confirm,
profile_info.name,
profile_contacts.remains,
profile_rating.rating
FROM profile_main
LEFT JOIN profile_info
ON profile_main.id=profile_info.profile_id
LEFT JOIN profile_contacts
ON profile_main.id=profile_contacts.profile_id
LEFT JOIN (
SELECT profile_rating.profile_id, SUM(profile_rating.rating)
FROM profile_rating
GROUP BY profile_rating.profile_id
) profile_rating
ON profile_main.id=profile_rating.profile_id
WHERE profile_main.user_id=$user_id
AND profile_main.deleted=0
The problem is LEFT JOIN with profile_rating. I need SUM(profile_rating.rating)
here is the profile_main table. table what saving all profiles
enter image description here
here is the profile_rating table. [edit] This table may not contain all profiles rating, just those wich were rated earlyer
id profile_id user_id rating ip_addr add_date deleted
--------------------------------------------------------------
1 16 5 15 111.111.111.111 123432433 0
2 16 5 17 111.111.111.111 123432433 0
3 16 5 25 111.111.111.111 123432433 0
4 16 5 34 111.111.111.111 123432433 0
5 16 5 12 111.111.111.111 123432433 0
If something else is needed, i will add it

Your query looks fine and it is a good idea to join pre-aggregated data, just as you are doing here. (A good habit in order not to mistakenly multiply the aggregates from one table with matches in another.)
But you access the field profile_rating.rating, which is not available, because you no longer deal with single record values, but sums. Make an alias name for the sum: SUM(rating) AS sum_rating and use that in your select clause.
SELECT
m.id,
m.add_date,
m.expire_date,
m.status_begin,
m.status_expire,
m.views,
m.last,
m.confirm,
i.name,
c.remains,
r.sum_rating
FROM profile_main m
LEFT JOIN profile_info i ON m.id = i.profile_id
LEFT JOIN profile_contacts c ON m.id = c.profile_id
LEFT JOIN
(
SELECT
profile_id,
SUM(rating) AS sum_rating
FROM profile_rating
GROUP BY profile_id
) r ON m.id = r.profile_id
WHERE m.user_id = $user_id
AND m.deleted = 0;
I also use table aliases to enhance readaility.

Why do you SELECT in the JOIN?
Just select the fields in your main select:
SELECT profile_main.id,
profile_main.add_date,
profile_main.expire_date,
profile_main.status_begin,
profile_main.status_expire,
profile_main.views,
profile_main.last,
profile_main.confirm,
profile_info.name,
profile_contacts.remains,
profile_rating.rating,
profile_rating.profile_id,
SUM(profile_rating.rating) AS rating_sum
FROM profile_main
LEFT JOIN profile_info
ON profile_main.id=profile_info.profile_id
LEFT JOIN profile_contacts
ON profile_main.id=profile_contacts.profile_id
LEFT JOIN profile_rating
ON profile_main.id=profile_rating.profile_id
WHERE profile_main.user_id=$user_id
AND profile_main.deleted=0
GROUP BY profile_rating.profile_id
So you get your summed rating back as rating_sum

you can try below query and let me know if need some thing else so that I can modify-
SELECT profile_main.id,
profile_main.add_date,
profile_main.expire_date,
profile_main.status_begin,
profile_main.status_expire,
profile_main.views,
profile_main.last,
profile_main.confirm,
profile_info.name,
profile_contacts.remains,
SUM(profile_rating.rating)
FROM profile_main
LEFT JOIN profile_info
ON profile_main.id=profile_info.profile_id
LEFT JOIN profile_contacts
ON profile_main.id=profile_contacts.profile_id
LEFT JOIN profile_rating
ON profile_main.id=profile_rating.profile_id
WHERE profile_main.user_id=$user_id
AND profile_main.deleted=0
GROUP BY profile_main.id

Similar questions has already been answered on SO. You are doing the groupby on your wrong column which is not available, use table alias as shown above answer. Please refer these links :
SQL Server Query LEFT JOIN, SUM and GROUP BY and I'm stumped!
And
Left join, sum and count group by

Related

Mysql - I have 3 unique tables, need a hint on getting the details with the count

I have 3 tables which are interconnected and i want to select columns from two tables and counts from table 3. If anyone is aware on this, any hint would be appreciated.
Below is the sql i tried, but the count is getting repeated
SELECT distinct p.p_id, p.p_f6, p.p_l4,m.m_id, (
SELECT COUNT(*)
FROM ttokens t where t.pdetail_id = p.pdetail_id
) AS token_count
FROM tparking p,ttokens t LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
WHERE t.pdetail_id = p.pdetail_id
You can try to use JOIN with subquery to get your count instead of selcet subquery.
SELECT p.p_id, p.p_f6, p.p_l4,m.m_id,t.cnt
FROM tparking p
JOIN (
SELECT pdetail_id,COUNT(*) cnt
FROM ttokens
GROUP BY pdetail_id
) t ON t.pdetail_id = p.pdetail_id
LEFT join ttokens_md m ON t.trefn_id = m.trefn_id
Note
I would use JOIN instead of , comma with where condition to connect two tables,, is an old style.

Syntax on update with multiple joins

I'm having an issue updating a table with a select using multiple joins. I feel like everything is in place but I'm getting some syntax problems around the end, as commented below.
UPDATE ambition.ambition_totals a
INNER JOIN (SELECT
c.user AS UserID,
COUNT(*) AS dealers,
ROUND((al.NumberOfDealers / al.NumberOfDealerContacts) * 100 ,2) AS percent
FROM contact_events c
JOIN users u
ON c.user = u.id
JOIN dealers d
ON c.dealer_num = d.dealer_num
LEFT JOIN (
SELECT user_id, COUNT(*) AS NumberOfDealerContacts,
SUM(CASE WHEN ( d.next_call_date + INTERVAL 7 DAY) THEN 1 ELSE 0 END) AS NumberOfDealers
FROM attr_list AS al
JOIN dealers AS d ON d.csr = al.data
WHERE al.attr_id = 14
GROUP BY user_id)) as al
ON al.user_id = a.ext_id -- this is where I have a syntax error
SET a.dealers_contacted = al.dealers,
a.percent_up_to_date = al.percent;
As shown, I'm getting the data needed from these joins but I'm unable to update based on my ON clause in the final join. The select itself works apart from this, but I'm just trying to alter it to update a table.
I'm sure I'm just overlooking something in the syntax but I get an error that 'every derived table must have its own alias'.
UPDATE
Original working select that needs to be converted into the update:
SELECT
c.user AS UserID,
COUNT(*) AS Number_of_recorded_events,
ROUND((al.NumberOfDealers / al.NumberOfDealerContacts) * 100 ,2) AS Percentage_up_to_date
FROM contact_events c
JOIN users u
ON c.user = u.id
JOIN dealers d
ON c.dealer_num = d.dealer_num
LEFT JOIN (
SELECT user_id, COUNT(*) AS NumberOfDealerContacts,
SUM(CASE WHEN ( d.next_call_date + INTERVAL 7 DAY) THEN 1 ELSE 0 END) AS NumberOfDealers
FROM jackson_id.attr_list AS al
JOIN jfi_dealers.dealers AS d ON d.csr = al.data
WHERE al.attr_id = 14
GROUP BY user_id) AS al
ON al.user_id = c.user
GROUP BY UserID;
'every derived table must have its own alias'
This error is pretty clear. A derived table is when you put a subquery in a FROM clause or JOIN clause, which you do twice in your query.
Every time you do this, you must give each of these derived table subqueries an alias, so you can reference columns returned by the subquery.
Like:
SELECT t.foo FROM (SELECT foo FROM MyTable) AS t
This must be done for every such subquery. In your case, you have something like this form:
UPDATE a
INNER JOIN (
SELECT ... FROM c JOIN u JOIN d
LEFT JOIN (SELECT ... FROM al JOIN d ...)
) AS al
SET ...
You have one level of subquery, which you give the alias al.
But you don't give an alias for the innermost subquery, the one you did a LEFT JOIN on. That one needs an alias too.
P.S.: This question is actually a duplicate of What is the error "Every derived table must have its own alias" in MySQL? from 2009. I know Stack Overflow encourages us to close new questions as duplicates if there is already an old answer. But I also know the reality is that people tend not to search old posts much.
On the other hand, that old Stack Overflow post from 2009 is literally the first result when I google for the error string 'every derived table must have its own alias'.

Remove duplicates of ONE table in a multiple JOIN result in My SQL

I am trying to display some info merging 4 tables. My tables are device, device_model, sub_product_area and borrow_device.
The problem I have is, when I link the tables to device table using a LEFT JOIN there are some duplicates for the transaction_ID from the borrow_device table. So I want to ORDER BY on transaction_Mode ONLY for that LEFT JOIN and only take the 'red' color relevant transaction_ID at such instances. I have tried SELECT DISTINCT but it didn't work. None of the similar question answers worked.
Here is my query ->
SELECT *
FROM device b
LEFT OUTER JOIN device_model a ON (b.`model_ID`=a.`model_ID`)
LEFT JOIN sub_product_area c ON (b.`sub_Product_Area_ID` = c.`sub_Product_Area_ID`)
LEFT JOIN borrow_device d ON (d.`device_ID` = b.`device_ID` and CURDATE() between from_Date and to_Date)
ORDER BY d.transaction_Mode DESC
My table structures are as below -:
Thanks in advance!
Adding a 'GROUP BY' to the end solved my problem. Thanks everyone!
device table and sub_product_area table have 2 field related are sub_product_area_id and product_area_id. in your SQl statement try to add "and b.product_Area_ID = c.product_Area_ID", so your syntax would be like this bellow :
SELECT *
FROM device b
LEFT OUTER JOIN device_model a ON (b.`model_ID`=a.`model_ID`)
LEFT JOIN sub_product_area c ON (b.`sub_Product_Area_ID` = c.`sub_Product_Area_ID` and b.`product_Area_ID` = c.`product_Area_ID`)
LEFT JOIN borrow_device d ON (d.`device_ID` = b.`device_ID` and CURDATE() between from_Date and to_Date)
ORDER BY d.transaction_Mode DESC

mysql join : i dont get rows with no corispondent in the left table , even when i use left join

i have 2 tables
1 - coupons
2 - tractions
for each coupon there might be couple of rows in tractions table
i want to have list of all coupons and count of it's tractions (void ones in this example)
SELECT `coupons`.*, count(tractions_void.id) as void
FROM `coupons`
LEFT JOIN `tractions` AS `tractions_void`
ON `tractions_void`.`coupon_parent` = `coupons`.`id`
AND `tractions_void`.`expired` = 1
WHERE `coupons`.`parent` =0
the problem is even though i use left join , in the output i only get coupons with at least 1 tractions .... basically i dont get the coupons with 0 tractions in the query result at all
i want to have them with 0 as tractions_void ... i thought if i use left join i wont have this problem ?
You need a group by clause:
SELECT c.*, count(t.id) as void
FROM coupons c LEFT JOIN
tractions t
ON t.coupon_parent = c.id AND
t.expired = 1
WHERE c.parent = 0
group by c.id;
I also replaced the table names with shorter aliases and removed the backticks to make the query more readable.
Your original query only returned one row, because it had an aggregation function in the select clause and no group by clause.
use this
SELECT `coupons`.*, count(tractions_void.id) as void
FROM `coupons`
LEFT JOIN `tractions` AS `tractions_void`
ON `tractions_void`.`coupon_parent` = `coupons`.`id`
WHERE `coupons`.`parent` =0
AND `tractions_void`.`expired` = 1
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----moved this here in where clause

how can use 1 cross join and 2 left join in one mysql query?

How can I use 1 cross join and 2 left joins (sum group by) in one MySQL db query?
The following works but the count results is wrong (it returns both COUNT - same result and wrong result).
SELECT
n_users.username, n_users.email,
COUNT(n_messages.ads_id ) AS msg_cnt,
COUNT(`n_coversation`.user_id ) AS cnv_cnt,
SUM(n_transaction.debit), SUM(n_transaction.credit)
FROM
n_users JOIN (n_ads , n_messages) ON
(n_ads.user_id=n_users.id AND n_messages.ads_id=n_ads.id )
LEFT JOIN n_coversation ON (n_coversation.user_id=n_users.id)
LEFT JOIN n_transaction ON (n_transaction.user_id=n_users.id)
WHERE
n_users.id =5
GROUP BY
n_transaction.user_id