Only use first of multiple matches SQL - mysql

I need to find the sum of credits from click_stats where source = 'reward' for all users who have claimed at least one of the 3 promo codes AND have the total clicks displayed.
Tables:
+---------------------------------------------+
| click_stats |
+----+---------+--------+--------+------------+
| ID | Credits | Userid | Source | Clicked |
+----+---------+--------+--------+------------+
| 1 | 10 | jon | reward | 1602216005 |
| 2 | 5 | bob | reward | 1602216504 |
| 3 | 5 | jon | reward | 1602216137 |
| 4 | 5 | bob | reward | 1602216138 |
| 5 | 10 | jon | reward | 1602216139 |
| 6 | 5 | jon | reward | 1602216140 |
| 7 | 10 | bob | reward | 1602216150 |
| 8 | 10 | jon | reward | 1602216150 |
| 9 | 10 | sue | reward | 1602216150 |
| 10 | 10 | sue | prize | 1602216150 |
+----+---------+--------+--------+------------+
+-----------------------+
| promo_used |
+----+--------+---------+
| id | userid | promoid |
+----+--------+---------+
| 1 | bob | 1 |
+----+--------+---------+
| 2 | bob | 2 |
+----+--------+---------+
| 3 | bob | 3 |
+----+--------+---------+
| 4 | jon | 1 |
+----+--------+---------+
| 5 | jon | 2 |
+----+--------+---------+
+------------------------+
| promo_codes |
+----+----------+--------+
| id | code | reward |
+----+----------+--------+
| 1 | forever1 | 20 |
+----+----------+--------+
| 2 | novgfy1 | 250 |
+----+----------+--------+
| 3 | novgfy2 | 500 |
+----+----------+--------+
My Query:
SELECT
click_stats.userid as Name,
sum(credits) as TotalClicks
FROM click_stats
JOIN promo_used
ON click_stats.userid = promo_used.userid
JOIN promo_codes
ON promo_used.promoid = promo_codes.id
WHERE
click_stats.source = 'reward'
and FROM_UNIXTIME(clicked) > '2020-10-08'
and (promo_codes.name like '%forever%'
or promo_codes.name like 'novgfy%')
group by
Name
having
TotalClicks > 10
Results when I run my query (returning the total number of clicks * number of promo codes used):
+--------------------+
| Results |
+------+-------------+
| Name | TotalClicks |
+------+-------------+
| bob | 60 |
+------+-------------+
| jon | 80 |
+------+-------------+
Results I am wanting (the total number of clicks only):
+--------------------+
| Expected Results |
+------+-------------+
| Name | TotalClicks |
+------+-------------+
| bob | 20 |
+------+-------------+
| jon | 40 |
+------+-------------+
The problem (I suspect) is that it is summing the click_stats every time it finds a match for promo_codes.name. I just need to know if one of them has been used and then return the total clicks for that user.

Your understanding of the problem is correct. The join multiplies the rows whenever a user has more than one of the promo codes, and you end up with the same credit summed several times.
I would recommend exists instead:
select cs.userid as name, sum(cs.credits) as totalclicks
from click_stats cs
where cs.source = 'reward' and exists (
select 1
from promo_used pu
inner join promo_codes pc on pc.id = pu.promoid
where
pu.userid = cs.userid
and (pc.name like '%forever%' or pc.name like 'novgfy%')
)
group by cs.userid
having sum(cs.credits) > 10

Related

Find first in where clause MYSQL

I've googled and searched here and maybe I don't know the exact way to write the question but can't find an answer...
I need to find the sum of credits from click_stats where source = 'reward' for all users who have claimed at least one of the 3 promo codes AND have the total clicks displayed. There are many more than the 3 but simplifed what I need to try to meet posting criteria.
Tables:
+---------------------------------------------+
| click_stats |
+----+---------+--------+--------+------------+
| ID | Credits | Userid | Source | Clicked |
+----+---------+--------+--------+------------+
| 1 | 10 | jon | reward | 1602216005 |
+----+---------+--------+--------+------------+
| 2 | 5 | bob | reward | 1602216504 |
+----+---------+--------+--------+------------+
| 3 | 5 | jon | reward | 1602216137 |
+----+---------+--------+--------+------------+
| 4 | 5 | bob | reward | 1602216138 |
+----+---------+--------+--------+------------+
| 5 | 10 | jon | reward | 1602216139 |
+----+---------+--------+--------+------------+
| 6 | 5 | jon | reward | 1602216140 |
+----+---------+--------+--------+------------+
| 7 | 10 | bob | reward | 1602216150 |
+----+---------+--------+--------+------------+
| 8 | 10 | jon | reward | 1602216150 |
+----+---------+--------+--------+------------+
+----+---------+--------+--------+------------+
| 9 | 10 | sue | reward | 1602216150 |
+----+---------+--------+--------+------------+
+----+---------+--------+--------+------------+
| 10 | 10 | sue | prize | 1602216150 |
+----+---------+--------+--------+------------+
+-----------------------+
| promo_used |
+----+--------+---------+
| id | userid | promoid |
+----+--------+---------+
| 1 | bob | 1 |
+----+--------+---------+
| 2 | bob | 2 |
+----+--------+---------+
| 3 | bob | 3 |
+----+--------+---------+
| 4 | jon | 1 |
+----+--------+---------+
| 5 | jon | 2 |
+----+--------+---------+
+------------------------+
| promo_codes |
+----+----------+--------+
| id | code | reward |
+----+----------+--------+
| 1 | forever1 | 20 |
+----+----------+--------+
| 2 | novgfy1 | 250 |
+----+----------+--------+
| 3 | novgfy2 | 500 |
+----+----------+--------+
My Query:
SELECT
click_stats.userid as Name,
sum(credits) as TotalClicks
FROM click_stats
JOIN promo_used
ON click_stats.userid = promo_used.userid
JOIN promo_codes
ON promo_used.promoid = promo_codes.id
WHERE
click_stats.source = 'reward'
and FROM_UNIXTIME(clicked) > '2020-10-09'
and (promo_codes.name like '%forever%'
or promo_codes.name like 'novgfy%')
group by
Name
having
TotalClicks > 10
Results when I run my query (returning the total number of clicks * number of promo codes used):
+--------------------+
| Results |
+------+-------------+
| Name | TotalClicks |
+------+-------------+
| bob | 60 |
+------+-------------+
| jon | 80 |
+------+-------------+
Results I am wanting (the total number of clicks only):
+--------------------+
| Expected Results |
+------+-------------+
| Name | TotalClicks |
+------+-------------+
| bob | 20 |
+------+-------------+
| jon | 40 |
+------+-------------+
The problem (I suspect) is that it is summing the click_stats every time it finds a match for promo_codes.name. I just need to know if one of them has been used and then return the total clicks for that user.
Don't join click_stats to the other tables because you will multiply the rows that you get by a factor equal to the number of rows of each user in promo_used.
Instead use the operator IN to filter the users:
SELECT Userid, SUM(Credits) TotalClicks
FROM click_stats
WHERE source = 'reward'
AND FROM_UNIXTIME(clicked) > '2020-10-09'
AND Userid IN (
SELECT pu.Userid
FROM promo_used pu INNER JOIN promo_codes pc
ON pc.id = pu.promoid
WHERE pc.code like '%forever%' OR pc.code like 'novgfy%'
)
GROUP BY Userid
HAVING TotalClicks > 10
Or:
SELECT Userid, SUM(Credits) TotalClicks
FROM click_stats
WHERE source = 'reward'
AND FROM_UNIXTIME(clicked) > '2020-10-09'
AND Userid IN (
SELECT pu.Userid FROM promo_used pu
WHERE EXISTS (
SELECT 1 FROM promo_codes pc
WHERE pc.id = pu.promoid AND (pc.code like '%forever%' OR pc.code like 'novgfy%' )
)
)
GROUP BY Userid
HAVING TotalClicks > 10
See the demo.
Results:
> Userid | TotalClicks
> :----- | ----------:
> bob | 20
> jon | 40

Mysql 2 select staments with value from statement 1 used in statement 2

How to join these to in one sql statement?
I have these 2 simple tables.
3_Referee_Matches
+------------------------------------+
| ID | CountryCode | RefereeUrlCode |
| 1 | eng | mike-jean |
| 2 | eng | mike-jean |
| 3 | eng | mike-jean |
| 4 | eng | mike-jean |
| 5 | spa | hulo-pape |
| 6 | ita | enri-tolsi |
| 7 | ita | enra-ean |
| 8 | ita | enra-ean |
+------------------------------------+
3_Players
+----------------------------------------------------+
| ID | MatchID | Name | PlayerUrlCode | Yellow |
| 1 | 1 | Mike Bell | mike-bell | 1 |
| 2 | 2 | Mike Bell | mike-bell | 1 |
| 3 | 3 | Thoms Tim | thoms-tim | 1 |
| 4 | 4 | Jean Claod | jean-claod | 0 |
| 5 | 33 | Thoms Tim | thoms-tim | 1 |
| 6 | 44 | Fis Most | fis-most | 0 |
| 7 | 54 | Geni Toens | geni-toens | 1 |
| 8 | 67 | Geni Toens | geni-toens | 1 |
+----------------------------------------------------+
Today i use these 2 select. But need help to combine them into one.
select 1:
SELECT rm.*, p.PlayerUrlCode AS VALUEtoBEusedAGAIN, COUNT(p.ID) AS YellowCounter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.CountryCode = 'eng' AND rm.RefereeUrlCode = 'mike-jean'
AND p.Yellow>0
GROUP BY p.Name
select 2:
SELECT COUNT(rm.ID) AS Counter
FROM 3_Referee_Matches rm
JOIN 3_Players p ON rm.ID = p.MatchID
WHERE rm.RefereeUrlCode='mike-jean'
AND p.PlayerUrlCode='VALUEtoBEusedAGAIN'
Result should be like this:
+--------------------------------------+
| Name | YellowCounter | Counter |
| Mike Bell | 2 | 2 |
| Jean Claod | 1 | 1 |
+--------------------------------------+
Showing that Mike Bell Got 2 yellow cards in 2 matches.
Your first query is nearly there. First, remove the extraneous columns from the select clause. count the number of "players" (really player information for each match) and sum their yellow cards.
select
p.name,
sum(yellow) as YellowCounter,
count(p.id) as Counter
from 3_Referee_Matches rm
join 3_Players p on rm.ID = p.MatchID
where rm.CountryCode = 'eng'
and rm.RefereeUrlCode = 'mike-jean'
group by p.name;
+------------+---------------+---------+
| name | YellowCounter | Counter |
+------------+---------------+---------+
| Mike Bell | 2 | 2 |
| Thoms Tim | 1 | 1 |
| Jean Claod | 0 | 1 |
+------------+---------------+---------+
I assume the example has Thoms and Jean reversed.

I want to ranking result with city based in mysql

I want to ranking result with city based in mysql
table1:-users
| user_id | marks |
--------------------
| 1 | 10 |
| 5 | 10 |
| 5 | 50 |
| 3 | 15 |
| 4 | 10 |
| 2 | 10 |
| 6 | 10 |
| 6 | 50 |
| 4 | 15 |
| 4 | 10 |
table:-2 users details
| user_id | city |
--------------------
| 1 | newdelhi |
| 2 | kolkata |
| 3 | mumbai |
| 4 | newdelhi |
| 5
| 6 | newdelhi |
I want to result like this:
| user_id | points |
--------------------
| 6 | 60 |
| 4 | 35 |
| 1 | 10 |
Try this :
SELECT
users.user_id
,SUM(users.marks) AS points
FROM
users
INNER JOIN
users_details ON users.user_id = users_details.user_id
WHERE
users_details.city = 'newdelhi'
GROUP BY
user_id

Show repeated max value

I have a table:
+----------------+----------------+------------------+-------+
| Student_Id | Student_Name | Assessment_Type | Mark |
+----------------+----------------+------------------+-------+
| 300 | John | Assignment | 1 |
| 200 | Liz | Final | 2 |
| 300 | John | Mid-term | 3 |
| 100 | Sue | Mid-term | 4 |
| 200 | Liz | Project | 5 |
| 300 | John | Assignment | 6 |
| 200 | Liz | Final | 7 |
| 300 | John | Mid-term | 8 |
| 100 | Sue | Mid-term | 8 |
| 200 | Liz | Project | 9 |
+----------------+----------------+------------------+-------+
I would like to find the max mark grouped by Assessment_Type, and if there is a duplicate, show both, so in this case:
+----------------+----------------+------------------+-------+
| Student_Id | Student_Name | Assessment_Type | Mark |
+----------------+----------------+------------------+-------+
| 300 | John | Assignment | 6 |
| 200 | Liz | Final | 7 |
| 300 | John | Mid-term | 8 |
| 100 | Sue | Mid-term | 8 |
| 200 | Liz | Project | 9 |
+----------------+----------------+------------------+-------+
What I have only shows one of them:
SELECT Student_Id, Student_Name, Assessment_Type, max(mark) FROM STUDENT_ASSESSMENT group by Student_Id, Assessment_Type;
Edit: Added more details to question.
You can find max marks in each assessment type and then compare that max(marks) and assessment type with each row.
select * from STUDENTS_ASSESSMENT where (Assessment_Type,marks) in
((select Assessment_Type,max(marks) from STUDENTS_ASSESSMENT groupby Assessment_Type));
You could find maximum value of the Mark column, then select rows that Mark value is equal to this value:
SELECT
Student_Id, Student_Name, Assessment_Type, Mark
FROM
STUDENT_ASSESSMENT FullSet
JOIN
(SELECT MAX(Mark) AS Mark FROM STUDENT_ASSESSMENT) MaxMark
USING (Mark);

Querying a many to many relationship in SQL

I have the following SQL relationship
user has many games
games has may users
User
----
id | name | age |
__________________
1 | mike | 11 |
2 | jeff | 12 |
3 | jake | 31 |
4 | lemd | 81 |
Game
-----
id | name | time |
_____________________
1 | froyo | 11:10 |
2 | honey | 12:22 |
3 | combb | 13:00 |
4 | lolli | 14:00 |
User_Game
----------
| userid | game_id |
___________________
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
| 4 | 3 |
| 1 | 2 |
| 2 | 4 |
| 2 | 1 |
For each of the users is there a way to get a
list of games that they have played including the number
of games that each user participated in.
Edit
I tried this query
Select User.name, User.age
from User
inner join User_Game
on User.id=User_Game.userid;
However not sure how I could add the count to it
SELECT
userid,
GROUP_CONCAT(game_id) as game_list,
COUNT(*) as total_games
FROM
USER_GAME
GROUP BY
userid;