I am trying to write an SQL query which will return a column of ID numbers for results, of which each team of people only appears with their best time.
In essence, it is a system which allows people to put in times for a relay event (like a swimming event with 4 team members), and will only show the best time for that team.
SQL Fiddle:
The only thing I can think of is doing a Group By on result.id and having a field which is GROUP_CONCAT(member_result.member_id ORDER BY member_result.member_id). I can then group on this, but then I get stuck.
Suggestions are very welcome.
As an aside, for non-relay events, this is the code I am using:
SELECT result_id FROM (
SELECT member_id,MIN(time) AS mintime
FROM result
JOIN member_result ON result.id = member_result.result_id
WHERE event_id = ?
GROUP BY member_id
ORDER BY mintime
) AS x
JOIN result ON result.time = x.mintime
JOIN member_result ON member_result.result_id = result.id AND member_result.member_id = x.member_id AND event_id = ?
GROUP BY member_result.member_id ORDER BY mintime
Related
Using this MySQL queries on my database:
SELECT movie.name, SUM(heroes.likes) AS 'success'
FROM heroebymovie JOIN
heroes
ON heroes.ID = heroebymovie.heroID JOIN
movie
ON movie.ID = heroebymovie.movieID
GROUP BY movie.ID
ORDER BY SUM(heroes.likes) DESC
I obtain this result:
|name |success |
|Avengers 2 |72317559 |
|Avengers |72317559 |
|Captain America : Civil War|67066832 |
I would like to display only the movies with the highest number of “success” (in this case “Avengers 2” and “Avengers”).
Can someone explain the way of doing it?
A simple way is using an having clause that filter for the max value ( in this case the ordered list of sum desc limit 1)
SELECT movie.name, SUM(heroes.likes) AS success
FROM heroebymovie JOIN heroes ON heroes.ID = heroebymovie.heroID
JOIN movie ON movie.ID = heroebymovie.movieID
GROUP BY movie.ID
HAVING success = (
SELECT SUM(heroes.likes)
FROM heroebymovie JOIN heroes ON heroes.ID = heroebymovie.heroID
JOIN movie ON movie.ID = heroebymovie.movieID
GROUP BY movie.ID
ORDER BY SUM(heroes.likes) DESC
LIMIT 1
)
ORDER BY SUM(heroes.likes) DESC
You are looking for a limit, but want to consider ties. MySQL supports the LIMIT clause, but unfortunately no accompanying ties expression.
In standard SQL you would simply add
FETCH 1 ROW WITH TIES;
and be done with it. (SQL Server does the same with TOP(1) WITH TIES.)
Another way would be to use standard SQL's MAX OVER: MAX(SUM(heroes.likes)) OVER() and only keep rows where the sum matches the maximum. Or use RANK OVER. But again, MySQL doesn't support either of these.
So your main option is to execute the query twice, like in this pseudo code:
select sum ... having sum = (select max(sum) ...)
An easy way to get the max of the sums in MySQL is to order by sums descending and limit the results to one row.
SELECT m.name, SUM(h.likes) AS "success"
FROM heroebymovie hm
JOIN heroes h ON h.ID = hm.heroID
JOIN movie m ON m.ID = hm.movieID
GROUP BY m.ID
HAVING SUM(h.likes) =
(
SELECT SUM(h2.likes)
FROM heroebymovie hm2
JOIN heroes h2 ON h2.ID = hm2.heroID
GROUP BY hm2.movieID
ORDER BY SUM(h2.likes) DESC
LIMIT 1
);
As per my requirement i made the below query. Now it not working.
Query is:
SELECT *
FROM T_INV_DTL T
LEFT JOIN (
SELECT inv_dtl_id,
Employee_id AS emp_id,
GROUP_CONCAT(DISTINCT Employee_id) AS Employee_id
FROM T_INV_INVESTIGATOR
GROUP BY
inv_dtl_id
)TII
ON T.inv_dtl_id = TII.inv_dtl_id
JOIN T_INVESTIGATION TI
ON T.inv_id = TI.inv_id
LEFT JOIN (
SELECT inv_dtl_id
FROM T_INV_BILL
GROUP BY
inv_dtl_id
)TIB
ON T.inv_dtl_id = TIB.inv_dtl_id
JOIN T_Insurance_company TIC
ON TI.client_id = TIC.ins_cmp_id
WHERE 1 T.Report_dt != '0000-00-00'
AND (
T.inv_dtl_id NOT IN (SELECT inv_dtl_id
FROM T_INV_BILL TIBS
WHERE TIBS.inv_dtl_id NOT IN (SELECT
inv_dtl_id
FROM
T_INV_BILL
WHERE
Bill_submitted_dt =
'0000-00-00'))
)
ORDER BY
Allotment_dt DESC
LIMIT 20
Can anyone tells the problem and can you please modify to more efficient query(Suppose if we have more than 100 records, then we take the count for it for pagination it should be give faster).
T_INV_DTL is main table and it connect to others. So my probelm is each entry of this table T_INV_DTL has multtiple investigation bill in the table T_INV_BILL. Report_dt in the T_INV_DTL. So my outcome is that i need result if there’s a report date in T_INV_DTL and not atleast one bill date in T_INV_BILL.
I need the result with both if there’s a report date in T_INV_DTL and not atleast one bill date in T_INV_BILL(If all have entered the bill submitted date it does not need it).
While I admittedly don't know what issues you're having (please provide addl info), your query does look like it could be optimized.
Removing your Where criteria and adding to your Join should save 2 of your table scans:
SELECT *
FROM T_INV_DTL T
LEFT JOIN (
SELECT inv_dtl_id,
Employee_id AS emp_id,
GROUP_CONCAT(DISTINCT Employee_id) AS Employee_id
FROM T_INV_INVESTIGATOR
GROUP BY
inv_dtl_id
)TII
ON T.inv_dtl_id = TII.inv_dtl_id
JOIN T_INVESTIGATION TI
ON T.inv_id = TI.inv_id
LEFT JOIN (
SELECT inv_dtl_id
FROM T_INV_BILL
WHERE Bill_submitted_dt != '0000-00-00'
GROUP BY inv_dtl_id
)TIB
ON T.inv_dtl_id = TIB.inv_dtl_id
JOIN T_Insurance_company TIC
ON TI.client_id = TIC.ins_cmp_id
WHERE T.Report_dt != '0000-00-00'
AND TIB.inv_dtl_id IS NULL
ORDER BY
Allotment_dt DESC
LIMIT 20
This is my current query to grab my deals:
SELECT deals.*, SUM(orders.cost) AS 'revenue' FROM deals
LEFT JOIN orders ON (orders.deal_id = deals.id)
WHERE 1
AND (orders.status = 'new' OR orders.status = 'delivered')
GROUP BY deals.ID
ORDER BY revenue ASC
Now this works great and i can sort this query by (order by) whatever field I wish in orders or deals table.
Then when i loop through the deals and display them with a foreach(),
I have this query to grab average review stars from customers for a deal:
SELECT ROUND(AVG(stars)) as 'avg_stars' FROM deals_reviews WHERE deal_id = *THE DEAL_ID* AND active = '1'
Now I would like to sort all the deals ASC/DESC out from the average stars.
To do this it require for me to merge that query with the above one, and when i need to display the avg_stars I grab this value from the first and only query and not a second query.
How can I have that query 'merged' into that first one? So when thats done we can just do ORDER BY avg_stars DESC and it'll sort by this?
I am not sure if i understand right, but this should be the solution
SELECT deals.*, SUM(orders.cost) AS 'revenue' FROM deals
LEFT JOIN orders ON (orders.deal_id = deals.id)
LEFT JOIN deals_reviews ON (deals.id = deals_reviews.deal_id AND active = '1')
WHERE 1
AND (orders.status = 'new' OR orders.status = 'delivered')
GROUP BY deals.ID
ORDER BY ROUND(AVG(stars)) as 'avg_stars' ASC
Ok I know this is going to sound stupid. But I have tried everything.
Here is my code to start of with
SELECT toD.username AS ToUser,
fromD.username AS FromUser,
rvw.* FROM usermessages AS rvw
LEFT JOIN users AS toD
ON toD.id = rvw.touserid
LEFT JOIN users AS fromD ON fromD.id = rvw.fromuserid
WHERE touserid = '" . $this->userid . "'
AND deleted = '0'
GROUP BY subkey
ORDER BY rvw.read ASC, rvw.created DESC
while this does work, what I am finding is that if there is a new message, and the read is 0 it still shows up as 1. I know this is because I am grouping the rows together.
But am not sure of any other way to do this.
It doesn't work because mysql can return any row from the group no matter how you try to order your set. To find first row in the group using some custom order you have to split it into two tasks - first finding all distinct values for the column you group by and then finding first row in the subquery for every referenced value. So your query should look like:
SELECT toD.username AS ToUser, fromD.username as FromUser, msg.* FROM
( SELECT DISTINCT touserid, subkey
FROM usermessages
WHERE touserid = 'insert_your_id_here'
AND deleted=0 ) msgg
JOIN usermessages msg
ON msg.id = ( SELECT msgu.id
FROM usermessages msgu
WHERE msgu.touserid = msgg.touserid
AND msgu.subkey = msgg.subkey
AND deleted=0
ORDER BY msgu.read ASC, msgu.created DESC
LIMIT 1 )
JOIN users fromD ON msg.fromuserid = fromD.id
JOIN users toD ON msg.touserid = toD.id
Make sure you have an index on (touserid,subkey). Depending on how big your db is you may need more.
Here is my problem :
I have 3 tables : account, account_event and account_subscription
account contains details like : company_name, email, phone, ...
account_event contains following events : incoming calls, outgoing calls, visit, mail
I use account_subscription in this query to retrieve the "prospects" accounts. If the account does not have a subscription, it is a prospect.
What I am using right now is the following query, which is working fine :
SELECT `account`.*,
(SELECT event_date
FROM clients.account_event cae
WHERE cae.account_id = account.id
AND cae.event_type = 'visit'
AND cae.event_done = 'Y'
ORDER BY event_date DESC
LIMIT 1) last_visit_date
FROM (`clients`.`account`)
WHERE (SELECT count(*)
FROM clients.account_subscription cas
WHERE cas.account_id = account.id) = 0
ORDER BY `last_visit_date` DESC
You can see that it returns the last_visit_date.
I would like to modify my query to return the last event details (last contact). I need the event_date AND the event_type.
So I tried the following query which is NOT working because apparently I can't get more than one column from my select subquery.
SELECT `account`.*,
(SELECT event_date last_contact_date, event_type last_contact_type
FROM clients.account_event cae
WHERE cae.account_id = account.id
AND cae.event_done = 'Y'
ORDER BY event_date DESC
LIMIT 1)
FROM (`clients`.`account`)
WHERE (SELECT count(*)
FROM clients.account_subscription cas
WHERE cas.account_id = account.id) = 0
ORDER BY `last_visit_date` DESC
I tried a lot of solutions around joins but my problem is that I need to get the last event for each account.
Any ideas?
Thank you in advance.
Jerome
Get a PRIMARY KEY in a subquery and join the actual table on it:
SELECT a.*, ae.*
FROM account a
JOIN account_event ae
ON ae.id =
(
SELECT id
FROM account_event aei
WHERE aei.account_id = a.id
AND aei.event_done = 'Y'
ORDER BY
event_date DESC
LIMIT 1
)
WHERE a.id NOT IN
(
SELECT account_id
FROM account_subscription
)
ORDER BY
last_visit_date DESC
Try moving the subquery to from part and alias it; it will look as just another table and you'll be able to extract more than one column from it.