MYSQL UPDATE for same id - mysql

IMPLEMENTATION: A buyer purchase a product and after it paid the product it will transfer to the seller balance.
PROBLEM: total.seller has id of 1,1,2 but it only manage to update 1,2 only and disregard the other 1 id. Any solution for this? to update same id
UPDATE tbclientdetails cd2
JOIN(
SELECT cd.client_id, cd.money_balance AS buyerbalance, lp.sellerid AS seller, lp.product_price AS price
FROM tbclientlogin cl
LEFT JOIN tbclientdetails cd ON cd.client_id = cl.client_login_id
LEFT JOIN tbclientrole cr ON cr.client_role_id = cd.role
LEFT JOIN tbpurchasedetails pd ON pd.client_purchase_id =cd.client_id
LEFT JOIN tbpaymentstatus ps ON ps.status_id = pd.payment_status
LEFT JOIN tblazardoproduct lp ON lp.product_id = pd.client_product_purchase_id
WHERE ps.status_option = "UNPAID" AND cd.client_email = "justin#gmail.com" AND cr.client_role_type = "BUYER"
) total
SET cd2.money_balance = total.price
WHERE cd2.client_id = total.seller

You don't want to join the single purchase rows, because then one table rows get several updates and the last one wins. You want one update per client with the SUM of the related unpaid purchases.
UPDATE tbclientdetails cd2
JOIN(
SELECT lp.sellerid AS seller, SUM(lp.product_price) AS price
FROM tbclientlogin cl
LEFT JOIN tbclientdetails cd ON cd.client_id = cl.client_login_id
LEFT JOIN tbclientrole cr ON cr.client_role_id = cd.role
LEFT JOIN tbpurchasedetails pd ON pd.client_purchase_id =cd.client_id
LEFT JOIN tbpaymentstatus ps ON ps.status_id = pd.payment_status
LEFT JOIN tblazardoproduct lp ON lp.product_id = pd.client_product_purchase_id
WHERE ps.status_option = 'UNPAID'
AND cd.client_email = 'justin#gmail.com'
AND cr.client_role_type = 'BUYER'
GROUP BY lp.sellerid
) total
SET cd2.money_balance = total.price
WHERE cd2.client_id = total.seller;
I am not sure about the rest. The client is the seller? And the balance is the sum of unpaid product prices? This may or may not be correct. I just copied it from your query. Also, I am not sure whether all the IDs are correctly stated. I just took what you showed us. Maybe you want to try the subquery as a standalone query first to see whether it gets yu what you expect.
At last: Your outer joins don't work. If there is a cl without a cd, then the outer joined row has nulls for all cd columns. WHERE cd.client_email = 'justin#gmail.com' dismisses hence all outer joined rows and you remain with a mere inner join. You should correct this by either moving the criteria to the ON clause to get the outer join working or by making the inner join explicit with INNER JOIN instead of LEFT [OUTER] JOIN.
By the way: string literals get quoted with single quotes in SQL. Double quotes are for names. Confusing the two can sometimes lead to unexpected results.

Related

Not getting the right results using GROUP_CONCAT in query

I have 7 tables to work with inside a query:
tb_post, tb_spots, users, td_sports, tb_spot_types, tb_users_sports, tb_post_media
This is the query I am using:
SELECT po.id_post AS id_post,
po.description_post as description_post,
sp.id_spot as id_spot,
po.date_post as date_post,
u.id AS userid,
u.user_type As tipousuario,
u.username AS username,
spo.id_sport AS sportid,
spo.sport_icon as sporticon,
st.logo_spot_type as spottypelogo,
sp.city_spot AS city_spot,
sp.country_spot AS country_spot,
sp.latitud_spot as latitudspot,
sp.longitud_spot as longitudspot,
sp.short_name AS spotshortname,
sp.verified_spot AS spotverificado,
u.profile_image AS profile_image,
sp.verified_spot_by as spotverificadopor,
uv.id AS spotverificador,
uv.user_type AS spotverificadornivel,
pm.media_type AS mediatype,
pm.media_file AS mediafile,
GROUP_CONCAT(tus.user_sport_sport) sportsdelusuario,
GROUP_CONCAT(logosp.sport_icon) sportsdelusuariologos,
GROUP_CONCAT(pm.media_file) mediapost,
GROUP_CONCAT(pm.media_type) mediaposttype
FROM tb_posts po
LEFT JOIN tb_spots sp ON po.spot_post = sp.id_spot
LEFT JOIN users u ON po.uploaded_by_post = u.id
LEFT JOIN tb_sports spo ON sp.sport_spot = spo.id_sport
LEFT JOIN tb_spot_types st ON sp.type_spot = st.id_spot_type
LEFT JOIN users uv ON sp.verified_spot_by = uv.id
LEFT JOIN tb_users_sports tus ON tus.user_sport_user = u.id
LEFT JOIN tb_sports logosp ON logosp.id_sport = tus.user_sport_sport
LEFT JOIN tb_post_media pm ON pm.media_post = po.id_post
WHERE po.status = 1
GROUP BY po.id_post,uv.id
I am having problems with some of the GROUP_CONCAT groups:
GROUP_CONCAT(tus.user_sport_sport) sportsdelusuario is giving me the right items but repeated, all items twice
GROUP_CONCAT(logosp.sport_icon) sportsdelusuariologos is giving me the right items but repeated, all items twice
GROUP_CONCAT(pm.media_file) mediapost is giving me the right items but repeated four times
GROUP_CONCAT(pm.media_type) mediaposttype s giving me the right items but repeated four times
I can put here all tables structures if you need them.
Multiple one-to-many relations JOINed in a query have a multiplicative affect on aggregation results; the standard solution is subqueries:
You can change
GROUP_CONCAT(pm.media_type) mediaposttype
...
LEFT JOIN tb_post_media pm ON pm.media_post = po.id_post
to
pm.mediaposttype
...
LEFT JOIN (
SELECT media_post, GROUP_CONCAT(media_type) AS mediaposttype
FROM tb_post_media
GROUP BY media_post
) AS pm ON pm.media_post = po.id_post
If tb_post_media is very big, and the po.status = 1 condition in the outer query would significantly reduce the results of the subquery, it can be worth replicating the original join within the subquery to filter down it's results.
Similarly, the correlated version I mentioned in the comments can also be more performant if the outer query has relatively few results. (Calculating the GROUP_CONCAT() for each individually can cost less than calculating it for all once if you would only actually using very few of the results of the latter).
or just add DISTINCT to all the group_concat, e.g., GROUP_CONCAT(DISTINCT pm.media_type)

SQL query - attempting to display results based on certain conditions using AND/OR and JOINS

Attempting to display all proposals in the system as long as they satisfy the following conditions:
the source must be supervisor
the status_code in the record table must not be 8 or 3
I have attempted a number of way in trying to make this work but I keep getting different data back which is not what I want.
The problem is how the tables have been set up. In theory a proposal can be applied for by a student and if that happens a record is automatically added to the 'record' table with a status set to '6' for pending. This status is then changed a number of times throughout the application process.
What I need is to show the users all proposals which have not been taken. The status codes to indicate this is '3' (accepted by a student so another student cannot take it) and '8' (not available).
NOTE: not all proposals may have a record in this table (a student has not applied for them)
This is the query so far which satisfies the first condition of being a "supervisor"
SELECT p.proposal_id, p.proposal_title,
p.description, u.user_record_id, u.forename,
u.surname, c.course_title, r.*,
GROUP_CONCAT(DISTINCT t.tag_title) AS tags
FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
GROUP BY p.proposal_id
My attempt at getting it to display all records which are available:
SELECT p.proposal_id, p.proposal_title,
p.description, u.user_record_id, u.forename,
u.surname, c.course_title, r.*,
GROUP_CONCAT(DISTINCT t.tag_title) AS tags
FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
AND (r.status_code != 3 OR r.status_code !=8)
GROUP BY p.proposal_id
The above query still returns proposals with the status code 3 and it fails to display any proposals which have yet not been applied for.
SQLFiddle Generated: http://sqlfiddle.com/#!9/b89a9/1/0
Any help would be much appreciated guys! Thank you.
Turned out I was missing a OR statement to achieve my goal.
To get the end result i needed, the query was modified to:
SELECT p.proposal_id, p.proposal_title, p.description, u.user_record_id, u.forename, u.surname, c.course_title, r.*, GROUP_CONCAT(DISTINCT t.tag_title) AS tags FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
AND (r.status_code not in (3,8) OR r.status_code IS NULL)
GROUP BY p.proposal_id
Successfully brings back all proposals which are available, are from the supervisor and those which have no record in the 'record' table.
Thank you to everyone who helped

Inner Join only returning values if match is in all four tables

I have the following INNER JOIN statement and It is only returning results if all four tables have a match for the order number in them.
I need it to include every result in the main table KC_Orders regardless of the equivalent contents of each INNER JOIN tables in the $sql
I understand that this is the point of the INNER JOIN but I need it do something else.
$sql = "SELECT *
FROM `KC_Orders`
INNER JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
INNER JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
INNER JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID";
$AllOrders = $db->query($sql);
Use left outer joins
SELECT *
FROM
`KC_Orders`
LEFT JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
LEFT JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
LEFT JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID
If there is always a status available, you can keep the inner join for the KC_Statuses table
SELECT *
FROM
A
LEFT JOIN B
ON A.id = B.id
... means that all the records from A will be returned and only the records from B that match a record from A. Records from A are returned even when there is no matching record in B.
It sounds like you want an OUTER JOIN rather than an INNER JOIN.
If you want all rows from the KC_Orders table, then put that table first in the FROM clause, and use a LEFT JOIN on the other tables. (The OUTER keyword is not required.) This will return all rows from the KC_Orders table, even if no matching row is found in the other tables. NULL values will be returned in place of value from "missing" rows.
SELECT *
FROM `KC_Orders`
LEFT
JOIN `KC_Payments`
ON KC_Orders.orderNumber = KC_Payments.orderNumber
LEFT
JOIN `KC_OrderStatus`
ON KC_Orders.orderNumber = KC_OrderStatus.orderNumber
LEFT
JOIN `KC_Statuses`
ON KC_OrderStatus.statusID = KC_Statuses.statusID

MySQL - LEFT JOIN failing when WHERE clause added

I have 4 tables as follows; SCHEDULES, SCHEDULE_OVERRIDE, SCHEDULE_LOCATION_OVERRIDES and LOCATION
I need to return ALL rows from all tables so running this query works fine, adding NULL values for any values that are not present:
SELECT.....
FROM (schedule s LEFT JOIN schedule_override so ON so.schedule_id = s.id)
LEFT JOIN schedule_location_override slo ON slo.schedule_override_id = so.id
LEFT JOIN location l ON slo.location_id = l.id
ORDER BY s.id, so.id, slo.id, l.id
I then need to restict results on the schedule_override end_date field. My problem is, as soon as I do this, no results for the SCHEDULE table are returned at all. I need all schedules to be returned, even if the overrides end_date criteria is not met.
Heres what I am using:
SELECT.....
FROM (schedule s LEFT JOIN schedule_override so ON so.schedule_id = s.id)
LEFT JOIN schedule_location_override slo ON slo.schedule_override_id = so.id
LEFT JOIN location l ON slo.location_id = l.id
WHERE so.end_date > '2011-01-30' OR so.end_date IS NULL
ORDER BY s.id, so.id, slo.id, l.id
Appreciate any thoughts/comments.
Best regards, Ben.
Have you tried putting it in the ON clause?
SELECT.....
FROM (schedule s LEFT JOIN schedule_override so ON so.schedule_id = s.id AND (so.end_date > '2011-01-30' OR so.end_date IS NULL))
LEFT JOIN schedule_location_override slo ON slo.schedule_override_id = so.id
LEFT JOIN location l ON slo.location_id = l.id
ORDER BY s.id, so.id, slo.id, l.id
That's a quite common mistake with outer Joins.
You need to put everything that limits the Join into the "ON" part for that table, otherwise you are effectively transforming the join to an inner one.
So move the WHERE clause in this case into the ON-part of the schedule_override and you should be fine.
Yes, when you left join, it could be that a row is not found, and the field is NULL in the result. When you add a condition in the WHERE clause, the value must match that condition, which it won't if it's NULL.
That shouldn't be a problem, because you explicitly check for NULL, so I don't really know why this condition fails, unless it does return a date, but that date is befor 2011-01-30.
Anyway, you could try to move the condition to the join. It will eliminate the need to check for NULL, although it shouldn't make a difference really.
SELECT.....
FROM
schedule s
LEFT JOIN schedule_override so
ON so.schedule_id = s.id
AND so.end_date > '2011-01-30'
...

Extra condition in ON clause is ignored

I have this query:
SELECT
TA.id,
T.duration,
DATE_FORMAT(TA.startTime,'%H:%i') AS startTime,
TEI.displayname,
TA.threatment_id,
TE.employeeid,
TTS.appointment_date
FROM
tblEmployee AS TE
INNER Join tblEmployeeInfo AS TEI ON TEI.employeeinfoid = TE.employeeinfoid
LEFT OUTER Join tblAppointment AS TA ON TE.employeeid = TA.employee_id
LEFT OUTER Join tblThreatment AS T ON TA.threatment_id = T.threatmentid
LEFT OUTER Join tblAppointments AS TTS ON TTS.id = TA.appointments_id
AND TTS.appointment_date = '2009-10-19'
LEFT OUTER Join tblCustomerCard AS TCC ON TCC.customercardid = TTS.customercard_id
WHERE
TE.employeeid = 1
What I try to accomplish is to select an employee, if available, all appointments at a given date. When there aren't any appointments, it should at least give the information about the employee.
But right now, it just gives all appointments related to an employee, and passes null when the date doesn't match. Whats going wrong here?
Because you are doing a left OUTER join, it will only join those records that match the On condition and will attach Null when the condition is not met.
You will still get records for which there is no Appointments on that date.
If you did an INNER join, then if the On condition is not met, no record will be output. So you will not get any records for which there are no appointments on that date.
Ok, not sure what database you are on, but this would work on SQL server :
select * from tblEmployee TA
...
left join
( select * from tblAppointments ed where ed.appointment_date = '10/01/2008' ) TTS
on ON TTS.id = TA.appointments_id
Thats the vibe anyway! You might need to tinker a bit.. Im at work and cant get the whole thing going for ya! :)