MySQL check if MAX value has duplicates - mysql

I'm running contests on my website. Every contest could have multiple entries. I want to retrieve if only the MAX value of votes has a duplicate.
The table is as follows:
contest_id entry_id votes
1 1 50
1 2 34
1 3 50
2 4 20
2 5 55
3 6 53
I just need the query to show me that contest 1 has a duplicate MAX value without additional information.
I tried this but didn't work:
SELECT MAX(votes) from contest group by contest_id having count(votes) > 1

SELECT a.contest_ID
FROM contest a
INNER JOIN
(
SELECT contest_id, MAX(votes) totalVotes
FROM contest
GROUP BY contest_id
) b ON a.contest_ID = b.contest_ID AND
a.votes = b.totalvotes
GROUP BY a.contest_ID
HAVING COUNT(*) >= 2
SQLFiddle Demo

This finds the max votes value per contest and counts the entries with that number of votes.
It then displays contest with more than one hit.
SELECT contest_id
FROM contests
WHERE votes=(
SELECT MAX(votes) FROM contests c WHERE c.contest_id=contests.contest_id
)
GROUP BY contest_id
HAVING COUNT(*) > 1;
SQLfiddle for testing.

You could do it by first selecting the maximum number of votes for each contest ID in a subquery, and then joining against the results (demo on SQLFiddle):
SELECT contest_id, votes
FROM contest
JOIN (
SELECT contest_id, MAX(votes) AS votes
FROM contest GROUP BY contest_id
) AS foo USING (contest_id, votes)
GROUP BY contest_id
HAVING COUNT(*) > 1
The nice thing about doing it like this is that it's an independent subquery, so MySQL only needs to rub it once.
Ps. Yes, this is basically identical to JW's answer, but I figured I'd leave it up anyway to show the slightly different syntax I used for the join.

Related

How to neglect duplicate value in MySQL?

I have a table where I am having duplicates value also.
From that table, I want to count duplicate value as 1.
I am using below query to find count
SELECT id, team, count(*) as votes FROM vot GROUP BY team ORDER BY votes DESC;
From this query, I get the duplicates count also.
I hope I made my query clear.
I am very new to MySQL.
What I got from your question is:
Instead of --
id team votes
1 A 2
3 C 2
2 B 1
you want --
id team votes
1 A 1
2 B 1
3 C 1
For this result use the following query:
SELECT id, team, count(distinct team) as votes FROM vot GROUP BY team,id ORDER BY votes DESC;

SQL count using multiple tables

Table 1: mappingtable (this contains the tags mapping with sentence)
id tag_id sentence_id
1 10 30
2 11 40
Table 2 reports
sentence_id DATE property (sentences may repeat)
30 timestamp1 property1
30 timestamp2 property2
40 timestamp3 property1
I am trying to get the tag ids and count of tags grouped by time.
I tried this query
SELECT DISTINCT(tag_id),COUNT(tag_id) AS cnt, MONTH(DATE) AS mnt
FROM mappingtable
INNER JOIN reports
ON mappingtable .sentence_id=reports.sentence_id AND reports.property= 'property1' GROUP BY tag_id,mnt ORDER BY cnt DESC;
However if the sentence repeats in the reports table (as is usually the case) the count of tags is coming wrong.
Edit:
EDIT
Tried the query suggested below:
SELECT M.tag_id, COUNT(M.tag_id) AS cnt, MONTH(R.DATE) AS mnt FROM mappingtable M INNER JOIN reports R ON M.sentence_id = R.sentence_id AND R.property = 'property1' GROUP BY M.tag_id, MONTH(R.DATE) ORDER BY COUNT(M.tag_id) DESC;
Even this query is giving additional counts because of repeating sentence ids.
What I need is the unique sentences for property property1 grouped by month and then the tags counts of those sentences.
tag_id cnt mnt
60865 145 11
60869 99 11
60994 74 11
61163 74 11
Something like this:
SELECT
M.tag_id,
COUNT(M.tag_id) AS cnt,
MONTH(R.DATE) AS mnt
FROM mappingtable M
INNER JOIN reports R
ON M.sentence_id = R.sentence_id
AND R.property = 'property1'
GROUP BY M.tag_id,
MONTH(R.DATE)
ORDER BY COUNT(M.tag_id) DESC;
The inner join would take the records common to both tables. I believe thats why you are getting a wrong count of tags. Even if a sentence has two properties, there would be just one occurrence in the join.

Mysql query statement to find how many time I am the max amount for a listing

Here is my tabel structure.
id
veh_id
user_id
amount
...
I have other tables to relate the user_id and veh_id as well.
I want to know how many times a user has put an amount on each veh_id and on how many occasions, this amount is actually the highest amount received. I would like to have those 2 counts for each user available.
id, veh_id, user_id, amount
1 1 30 100
2 1 32 105
3 2 30 100
4 2 32 95
5 2 33 90
I would like the select statement to give me:
user 30 as bid 2 times and 1 time is the higest bidder
user 32 as bid 2 time ans 1 time is the higest bidder
user 33 bid 1 time and 0 time the highest bidder
I don't know if it is possible to get those numbers.
This might be close, not sure exactly how you're relating vehicles together.
select
user_id,
count(*) as num_bids,
SUM(is_highest) as max_bids
from ( select
a.user_id,
COALESCE((select
MAX(b.amount) < a.amount
from bid as b
where b.id < a.id
and b.veh_id=a.veh_id
), 1) as is_highest
from bid as a
) as c
group by user_id
My understanding is user 30 has 2 max bids (2 first bids on a vehicle).
EDIT: If you're just looking for total 1 max bid per vehicle, let me know. That's actually a lot easier than rolling back to see who's bids were max when they came in...
EDIT2: Solution for only 1 max counts per vehicle:
Seems like this should be simpler for some reason:
select
user_id,
count(*) as num_bids,
count(vamt) as num_max
from bid
left join (
select veh_id as vid, max(amount) as vamt
from bid
group by veh_id
) as a on vid = veh_id and vamt <= amount
group by user_id
Try this,
select x.user_id, x.bid_times, COALESCE(y.max_times,0) as max_times from
(select user_id, count(*) as bid_times from testt group by user_id) as x
LEFT JOIN
(select user_id, count(*) as max_times from testt a where 0=( select count(*) from testt where amount > a.amount and veh_id=a.veh_id ) group by user_id) as y
ON x.user_id=y.user_id

MySQL query problems with combined SUM

I have three tables here, that I'm trying to do a tricky combined query on.
Table 1(teams) has Teams in it:
id name
------------
150 LA Lakers
151 Boston Celtics
152 NY Knicks
Table 2(scores) has scores in it:
id teamid week score
---------------------------
1 150 5 75
2 151 5 95
3 152 5 112
Table 3(tickets) has tickets in it
id teamids week
---------------------
1 150,152,154 5
2 151,154,155 5
I have two queries that I'm trying to write
Rather than trying to sum these each time i query the tickets, I've added a weekly_score field to the ticket. The idea being, any time a new score is entered for the team, I could take that teams id, get all tickets that have that team / week combo, and update them all based on the sum of their team scores.
I've tried the following to get the results i'm looking for (before I try and update them):
SELECT t.id, t.teamids, (
SELECT SUM( s1.score )
FROM scores s1
WHERE s1.teamid
IN (
t.teamids
)
AND s1.week =11
) AS score
FROM tickets t
WHERE t.week =11
AND (t.teamids LIKE "150,%" OR t.teamids LIKE "%,150")
Not only is the query slow, but it also seems to not return the sum of the scores, it just returns the first score in the list.
Any help is greatly appreciated.
If you are going to match, you'll need to accommodate for the column only having one team id. Also, you'll need to LIKE in your SELECT sub query.
SELECT t.id, t.teamids, (
SELECT SUM( s1.score )
FROM scores s1
WHERE
(s1.teamid LIKE t.teamids
OR CONCAT("%,",s1.teamid, "%") LIKE t.teamids
OR CONCAT("%",s1.teamid, ",%") LIKE t.teamids
)
AND s1.week =11
) AS score
FROM tickets t
WHERE t.week =11
AND (t.teamids LIKE "150,%" OR t.teamids LIKE "%,150" OR t.teamids LIKE "150")
You don't need SUM function here ? The scores table already has it? And BTW, avoid subqueries, try the left join (or left outer join depending on your needs).
SELECT t.id, t.name, t1.score, t2.teamids
FROM teams t
LEFT JOIN scores t1 ON t.id = t1.teamid AND t1.week = 11
LEFT JOIN tickets t2 ON t2.week = 11
WHERE t2.week = 11 AND t2.teamids LIKE "%150%"
Not tested.
Well not the most elegant query ever, but it should word:
SELECT
tickets.id,
tickets.teamids,
sum(score)
FROM
tickets left join scores
on concat(',', tickets.teamids, ',') like concat('%,', scores.teamid, ',%')
WHERE tickets.week = 11 and concat(',', tickets.teamids, ',') like '%,150,%'
GROUP BY tickets.id, tickets.teamids
or also this:
SELECT
tickets.id,
tickets.teamids,
sum(score)
FROM
tickets left join scores
on FIND_IN_SET(scores.teamid, tickets.teamids)>0
WHERE tickets.week = 11 and FIND_IN_SET('150', tickets.teamids)>0
GROUP BY tickets.id, tickets.teamids
(see this question and the answers for more informations).

Get User Rank Based on Sum with Pagination

There are several rank posts out there but I have yet to see one dealing with when the results are paginated and when the ranking criteria (in this case: points) is equal to the previous user. I have tried a few of the pre-existing examples but none have worked.
I have a table called "users" with the column "id". I also have a table called "points" with the columns "user_id" and "amount".
I need:
1.) Users with duplicate sum of points to have the same rank
Points Table
user_id amount
1 10
2 20
1 5
3 20
3 -5
4 5
Rank should be
rank user_id total
1 2 20
2 1 15
2 3 15
3 4 5
2.) Needs to maintain the ranking from one page to another so the rank has to be gathered in the query and not the resulting PHP.
3.) Display ALL users not just ones with rows in the points table because some users have 0 points and I want to display them last.
Right now I'm just listing the users in order of their points but their rank is not gathered because it wasn't working.
$getfanspoints = mysql_query("SELECT DISTINCT id,
(SELECT SUM(amount) AS points FROM points WHERE points.user_id = users.id) AS points
FROM users
ORDER BY points DESC LIMIT $offset, $fans_limit", $conn);
I've read these solutions and none have worked.
[Roland's Blog][1]
[How to get rank based on SUM's][2]
[MySQL, get users rank][3]
[How to get rank using mysql query][4]
and a few others whose link I can't find right now.
Any suggestions?
[EDIT]
I used ypercube's bottom answer.
SELECT COUNT(*) AS rank
, t.user_id
, t.total
FROM
( SELECT user_id
, SUM(amount) AS total
FROM points
GROUP BY user_id
) AS t
JOIN
( SELECT DISTINCT
SUM(amount) AS total
FROM points
GROUP BY user_id
) AS dt
ON
t.total <= dt.total
GROUP BY t.user_id
ORDER BY rank
, user_id
But the above may be really slow with a big table and points awarded often. It might be really better to have just this and calculate the ranks in your application code:
SELECT users.id AS user_id
, SUM(amount) AS total
FROM
users
LEFT JOIN
points
ON points.user_id = users.id
GROUP BY users.id
ORDER BY total DESC
, user_id
This will work, too (edited, to work with the users table and with OFFSET):
SELECT *
FROM
( SELECT
#rank := #rank + (#t <> total) AS rank
, user_id
, #t := total AS total
FROM
( SELECT users.id AS user_id
, COALESCE(SUM(amount),0) AS total
FROM users
LEFT JOIN points
ON users.id = points.user_id
GROUP BY users.id
) AS o
CROSS JOIN
( SELECT #rank := 0, #t := -999999
) AS dummy
ORDER BY total DESC
, user_id
) tmp
LIMIT x OFFSET y