I have 2 tables, one with a set of proposals and one with votes cast on the proposals, both joined with a unique ID.
The proposals table has a date field when the proposal was started, the votes have a date when the vote was cast. The proposal is marked as "success" when enough votes are cast. I want to find out how many days it takes in average to close votes.
My initial approach was to create a query that lists each proposal with the most recent vote through a left join:
SELECT proposals.pr_id, DATEDIFF(MAX(proposals_votes.`date`), proposals.`date`)
FROM proposals
LEFT JOIN proposals_votes ON proposals.pr_id = proposals_votes.pr_id
WHERE STATUS = 'success'
The issue is that this returns only one line, which is a surprise to me. I would have thought the MAX is done on the LEFT JOIN table and not on the resulting table.
Is there a way to do this within the LEFT JOIN or do I need to do a sub-query?
Use GROUP BY clause on pr_id to fetch no of days for each proposals
Try this:
SELECT p.pr_id, DATEDIFF(MAX(pv.`date`), p.`date`)
FROM proposals p
LEFT JOIN proposals_votes pv ON p.pr_id = pv.pr_id
WHERE pv.status = 'success'
GROUP BY p.pr_id;
If you want to multiple line you should use GROUP BY because of aggregate function always return only one rows. You will get multiple rows result by GROUP BY parameter like GROUP BY proposals.pr_id.
SELECT
proposals.pr_id,
DATEDIFF(MAX(proposals_votes.date),proposals.date)
FROM
proposals
LEFT JOIN
proposals_votes ON proposals.pr_id = proposals_votes.pr_id
WHERE
STATUS = 'success'
GROUP BY proposals.pr_id;
Related
I tried to write a query, but unfortunately I didn't succeed.
I want to know how many packages delivered over a given period by a person.
So I want to know how many packages were delivered by John (user_id = 1) between 01-02-18 and 28-02-18. John drives another car (another plate_id) every day.
(orders_drivers.user_id, plates.plate_name, orders.delivery_date, orders.package_amount)
I have 3 table:
orders with plate_id delivery_date package_amount
plates with plate_id plate_name
orders_drivers with plate_id plate_date user_id
I tried some solutions but didn't get the expected result. Thanks!
Try using JOINS as shown below:
SELECT SUM(o.package_amount)
FROM orders o INNER JOIN orders_drivers od
ON o.plate_id=od.plate_id
WHERE od.user_id=<the_user_id>;
See MySQL Join Made Easy for insight.
You can also use a subquery:
SELECT SUM(o.package_amount)
FROM orders o
WHERE EXISTS (SELECT 1
FROM orders_drivers od
WHERE user_id=<user_id> AND o.plate_id=od.plate_id);
SELECT sum(orders.package_amount) AS amount
FROM orders
LEFT JOIN plates ON orders.plate_id = orders_drivers.plate_id
LEFT JOIN orders_driver ON orders.plate_id = orders_drivers.plate_id
WHERE orders.delivery_date > date1 AND orders.delivery_date < date2 AND orders_driver.user_id = userid
GROUP BY orders_drivers.user_id
But seriously, you need to ask questions that makes more sense.
sum is a function to add all values that has been grouped by GROUP BY.
LEFT JOIN connects all tables by id = id. Any other join can do this in this case, as all ids are unique (at least I hope).
WHERE, where you give the dates and user.
And GROUP BY userid, so if there are more records of the same id, they are returned as one (and summed by their pack amount.)
With the AS, your result is returned under the name 'amount',
If you want the total of packageamount by user in a period, you can use this query:
UPDATE: add a where clause on user_id, to retrieve John related data
SELECT od.user_id
, p.plate_name
, SUM(o.package_amount) AS TotalPackageAmount
FROM orders_drivers od
JOIN plates p
ON o.plate_id = od.plate_id
JOIN orders o
ON o.plate_id = od.plate_id
WHERE o.delivery_date BETWEEN convert(datetime,01/02/2018,103) AND convert(datetime,28/02/2018,103)
AND od.user_id = 1
GROUP BY od.user_id
, p.plate_name
It groups rows on user_id and plate_name, filter a period of delivery_date(s) and then calculate the sum of packageamount for the group
I'm having some trouble formulating a complex SQL query. I'm getting the result I'm looking for and the performance is fine but whenever I try to grab distinct rows for my LEFT JOIN of product_groups, I'm either hitting some performance issues or getting incorrect results.
Here's my query:
SELECT
pl.name, pl.description,
p.rows, p.columns,
pr.sku,
m.filename, m.ext, m.type,
ptg.product_group_id AS group,
FROM
product_region AS pr
INNER JOIN
products AS p ON (p.product_id = pr.product_id)
INNER JOIN
media AS m ON (p.media = m.media_id)
INNER JOIN
product_language AS pl ON (p.product_id = pl.product_id)
LEFT JOIN
products_groups AS ptg ON (ptg.product_id = pr.product_id)
WHERE
(pl.lang = :lang) AND
(pr.region = :region) AND
(pt.product_id = p.product_id)
GROUP BY
p.product_id
LIMIT
:offset, :limit
The result I'm being given is correct however I want only distinct rows returned for "group". For example I'm getting many results back that have the same "group" value but I only want the first row to show and the following records that have the same group value to be left out.
I tried GROUP BY group and DISTINCT but it gives me incorrect results. Also note that group can come back as NULL and I don't want those rows to be effected.
Thanks in advance.
I worked out a solution an hour after posting this. My goal was to group by product_group_id first and then the individual product_id. The requirement was that I would eliminate product duplicates and have ONE product represent the group set.
I ended up using COALESCE(ptg.product_group_id, p.product_id). This accounts for the fact that most of my group IDs were null except for a few dispersed products. In using COALESCE I'm first grouping by the group ID, if that value is null it ignores the group and collects by product_id.
Please have a look at the below SQL Query
SELECT Client_Portfolio.*,
Client.Name AS "Client Name",
Provider.Name AS "Provider Name",
Initial_Fees.*,
Portfolio.VAT,
Portfolio.Invest_Amount,
Portfolio.Cash_Value,
SUM(Ongoing_Fees.Fee)
FROM Client_Portfolio
LEFT JOIN Client ON Client.idClient = Client_Portfolio.idClient
LEFT JOIN Portfolio ON Portfolio.idPortfolio = Client_Portfolio.idPortfolio
LEFT JOIN Provider ON Provider.idProvider = Portfolio.idProvider
LEFT JOIN Initial_Fees ON Initial_Fees.idPortfolio = Portfolio.idPortfolio
LEFT JOIN Ongoing_Fees ON Ongoing_Fees.idPortfolio = Portfolio.idPortfolio
ORDER BY Client_Portfolio.idClient
This query generates incorrect results, but if I remove the "SUM(Ongoing_Fees.Fee)" part, then this generates the correct result.
Ongoing_Fees is a Table, and some Portfolios might have Ongoing_Fees, while others don't. I was trying to Sum the total Ongoing_Fees belong to each portfolio seperatly and get the result with the above query. But it went wrong.. It gave me the Ongoing_Fees sum of the entire table, and the entire above query returned just 1 row! How can I fix this?
You are using aggregate function sum() without group by so it will give you one single row.
If you want to get the result of sum per group then you must use group by clause at the end.
From the discussion you may need to add
group by Portfolio.idPortfolio before the order by clause.
This will give you sum value per idPortfolio from the selection.
Check here more on it http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html
I need a query. I'm trying to sum of one field with joined tables. Some records not in second table. So this records sum should be zero. But the query only sum the records which are in the second table.
select s.*,sum(sd.fiyat) as konak from fuar_sozlesme1 s
left outer join fuar_sozlesme1_detay sd on (sd.sozlesme_id = s.id)
------EDIT-------
I added group by into the query and solved my problem. Here is the new ;
select s.*,sum(sd.fiyat) as konak from fuar_sozlesme1 s
left outer join fuar_sozlesme1_detay sd on (sd.sozlesme_id = s.id)
group by sd.sozlesme_id
I thinik you need to use IFNULL(sd.fiyat,0) instead of sd.fiyat to get zeros for the NULL values coming from the second table because of the LEFT JOIN like so:
SELECT s.*, SUM(IFNULL(sd.fiyat, 0)) as konak
FROM fuar_sozlesme1 s
LEFT OUTER JOIN fuar_sozlesme1_detay sd ON sd.sozlesme_id = s.id
GROUP BY s.someFields
Here is a simple example, you may help: http://sqlfiddle.com/#!2/41481/1
This is an old thread, but I spent a couple of hours trying to solve the same issue.
My query has two joins, a filter and a SUM function. I'm no SQL expert, but this helped me achieve the desired result of still showing a result even if the joined table had no rows to sum.
The key for me in order to show results even if the sum was totaling nothing, was the GROUP BY. I'm still not 100% sure why.
The two types of joins were chosen based on this article - MySQL Multiple Joins in one query?
SELECT registrations.reg_active, registrations.team_id, registrations.area_id, registrations.option_id, registrations.reg_fund_goal, registrations.reg_type, registrations.reg_fee_paid, registrations.reg_has_avatar, users.user_name, users.user_email, users.user_phone, users.user_zip, users.user_age, users.user_gender, users.user_active, SUM(IFNULL(donations.donation_amount,0)) as amt from registrations
INNER JOIN `users`
ON registrations.user_id = users.user_id
AND registrations.event_id = :event_id
LEFT OUTER JOIN `donations`
ON registrations.reg_id = donations.reg_id
GROUP BY donations.reg_id
ORDER BY users.user_name ASC
Trying to join a table "fab_qouta.qoutatype" to at value inside a sub query "fab_status_members.statustype" but it returns nothing.
If I join the 2 tables directly in a query the result is correct.
Like this:
select statustype, takst
from
fab_status_members AS sm
join fab_quota as fq
ON fq.quotatype = sm.statustype
So I must be doing something wrong, here the sub query code, any help appreciated
select
ju.id,
name,
statustype,
takst
from jos_users AS ju
join
( SELECT sm.Members AS MemberId, MaxDate , st.statustype
FROM fab_status_type AS st
JOIN fab_status_members AS sm
ON (st.id = sm.statustype) -- tabels are joined
JOIN
( SELECT members, MAX(pr_dato) AS MaxDate -- choose members and Maxdate from
FROM fab_status_members
WHERE pr_dato <= '2011-07-01'
GROUP BY members
)
AS sq
ON (sm.members = sq.members AND sm.pr_dato = sq.MaxDate)
) as TT
ON ju.id = TT.Memberid
join fab_quota as fq
ON fq.quotatype = TT.statustype
GROUP BY id
Guess the problem is in the line: join fab_quota as fq ON fq.quotatype = TT.statustype
But I can't seem to look through it :-(
Best regards
Thomas
It looks like you are joining down to the lowest combination of per member with their respective maximum pr_dato value for given date. I would pull THIS to the FIRST query position instead of being buried, then re-join it to the rest...
select STRAIGHT_JOIN
ju.id,
ju.name,
fst.statustype,
takst
from
( SELECT
members,
MAX(pr_dato) AS MaxDate
FROM
fab_status_members
WHERE
pr_dato <= '2011-07-01'
GROUP BY
members ) MaxDatePerMember
JOIN jos_users ju
on MaxDatePerMember.members = ju.ID
JOIN fab_status_members fsm
on MaxDatePerMember.members = fsm.members
AND MaxDatePerMember.MaxDate = fsm.pr_dato
JOIN fab_status_type fst
on fsm.statustype = fst.id
JOIN fab_quota as fq
on fst.statusType = fq.quotaType
I THINK I have all of what you want, and let me reiterate in simple words what I think you want. Each member can have multiple status entries (via Fab_Status_Members). You are looking for all members and what their MOST RECENT Status is as of a particular date. This is the first query.
From that, whatever users qualify, I'm joining to the user table to get their name info (first join).
Now, back to the complex part. From the first query that determined the most recent date status activity, re-join back to that same table (fab_status_members) and get the actual status code SPECIFIC to the last status date for that member (second join).
From the result of getting the correct STATUS per Member on the max date, you need to get the TYPE of status that code represented (third join to fab_status_type).
And finally, from knowing the fab_status_type, what is its quota type.
You shouldn't need the group by since the first query is grouped by the members ID and will return a single entry per person (UNLESS... its possible to have multiple status types in the same day in the fab_status_members table... unless that is a full date/time field, then you are ok)
Not sure of the "takst" column which table that comes from, but I try to completely qualify the table names (or aliases) they are coming from, buy my guess is its coming from the QuotaType table.
... EDIT from comment...
Sorry, yeah, FQ for the last join. As for it not returning any rows, I would try them one at a time and see where the break is... I would start one at a time... how many from the maxdate query, then add the join to users to make sure same record count returned. Then add the FSM (re-join) for specific member / date activity, THEN into the status type... somewhere along the chain its missing, and the only thing I can think of is a miss on the status type as any member status would have to be associated with one of the users, and it should find back to itself as that's where the max date originated from. I'm GUESSING its somewhere on the join to the status type or the quota.