sql query to count votes, groub by candidate_id, position_id - mysql

table VOTES
id
voters_id
candidate_id
positions_id
1
xxx
18
6
2
xxx
18
6
3
xxx
18
6
4
xxx
18
6
5
xxx
19
6
6
xxx
19
6
7
xxx
22
20
8
xxx
22
20
table POSITIONS
id
title
6
president
20
mayor
table candidates
id
name
18
mark
19
john
22
eddie
I HAVE THESE THEERE TABLES, I NEED A QUERY FOR THIS OUTPUT
total_votes
candidate_id
candidate_name
position_id
position_name
4
18
mark
6
president
2
19
mark
6
president
2
22
eddie
20
mayor

Use:
select v.total_votes,
v.candidate_id,
c.name as candidate_name,
v.position_id ,
p.title as position_name
from (select COUNT(*) as total_votes,
candidate_id,
position_id
from votes
GROUP BY candidate_id, position_id
) as v
INNER JOIN positions p on v.position_id=p.id
INNER JOIN candidates c on c.id=v.candidate_id ;
Result:
total_votes candidate_id candidate_name position_id position_name
4 18 mark 6 president
2 19 john 6 president
2 22 eddie 20 mayor
Note. Aggregation always comes after the join, that's why you need to do the aggregation on a subquery
https://dbfiddle.uk/7q9GUm0y
can i ask, if i would add the percentage, counting the SUM of total
votes, on the votes obteined from a single candidate, how should i do
it?
select v.total_votes,
round(((v.total_votes * 100) / temp.tot_voters),2) AS Percentage,
concat(round(((v.total_votes * 100) / temp.tot_voters),2),'%') AS Percentage_1,
v.candidate_id,
c.name as candidate_name,
v.position_id ,
p.title as position_name
from (select COUNT(*) as total_votes,
candidate_id,
position_id
from votes
GROUP BY candidate_id, position_id
) as v
CROSS JOIN (select count(voters_id) as tot_voters from votes) temp
INNER JOIN positions p on v.position_id=p.id
INNER JOIN candidates c on c.id=v.candidate_id ;
https://dbfiddle.uk/wBTbVVlf

Related

SQL: how to get membership based on ALL from a given cohort

I have the following tables in a MySQL database:
team
team_id name
3 Rangers
12 Capitals
19 Red Wings
4 Bruins
212 Avalanche
102 Flyers
20 Islanders
50 Sabres
7 Stars
player
id name
2 Zach
1 Deb
17 William
9 Viktor
12 Andrew
41 Chris
22 Bobby
5 Phil
3 Roy
92 Li
6 Juan
players_in
team_id player_id points
3 2 42
212 2 19
3 12 18
19 12 2
3 41 2
4 41 1
212 41 78
212 17 1
19 41 4
12 41 2
3 17 6
4 1 9
102 1 40
102 22 7
20 22 19
20 5 22
50 3 20
12 92 15
12 17 8
7 6 12
Here is a SQL Fiddle with the data: http://www.sqlfiddle.com/#!9/989ebe/1
I would like to get the name and id of the players who have played on ALL of the teams that Zach has played on.
In this case, Zach has played for the Rangers and the Avalanche.
Therefore, the desired result set would be:
name id
William 17
Chris 41
(because these players were part of both the Rangers and the Avalanche teams)
How would I do this?
Thanks!
select distinct p.*
from player p
join players_in pi on pi.player_id = p.id
join player p2 on p2.name = 'Zach'
join players_in pi2 on pi2.team_id = pi.team_id
and pi2.player_id = p2.id
where
p.name <> 'Zach'
and not exists (select 1 from players_in pi3
where pi3.player_id = p2.id
and pi3.team_id not in (select team_id
from players_in pi4
where pi4.player_id = p.id));
First of all I've joined players_in (pi) with players (p) obtaining the set of all players and theirs teams.
Second, cross joined player zack joined with player_in (pi2) obtaining the set of Zach's teams. Joined pi2 with pi I've obtained the set of all player that had played in a Zach's team.
Now the where conditions:
p.name <> 'Zach' will exclude Zach from my list.
The not exists condition is the hard part of the query.
I've selected all Zach teams again (pi3) not in the set of the player's (p) team,
SQL Fiddle here
Your requirement could be translated to: searching for players which there's not exists any Jack's team that they don't play in. Corresponding query could be:
SELECT
DISTINCT p1.name, p1.id
FROM
player p1
INNER JOIN players_in pin1 ON p1.id = pin1.player_id
WHERE
name != 'Zach'
AND NOT EXISTS (
SELECT 1
FROM
team t
INNER JOIN players_in pin2 ON t.team_id = pin2.team_id
INNER JOIN player p2 ON p2.id = pin2.player_id
WHERE
p2.name = 'Zach'
AND NOT EXISTS (SELECT 1
FROM players_in pin3
WHERE pin2.team_id = pin3.team_id
AND pin1.player_id = pin3.player_id)
);
Demo: http://www.sqlfiddle.com/#!9/989ebe/61
Using a cte for Zach's games and then checking all potential memberships based on team_id existence in the cte's values:
with cte as (
select pi1.team_id from players_in pi1 join player p2 on p2.id = pi1.player_id
where p2.name = 'Zach'
)
select p.* from player p where (select count(*) from cte c) = (select
sum(pi1.team_id in (select c.team_id from cte c))
from players_in pi1 where pi1.player_id = p.id) and p.name != 'Zach'
See fiddle.

multiple selects with different where conditions and limits

I have a high scores table that is slightly more complicated because scores are tracked in rounds (round 1, round 2, round 3, etc.). Sample table:
scoreID
roundID
userID
score
1
1
2
25
2
1
3
12
3
1
4
14
4
1
5
6
5
2
2
39
6
2
3
23
7
2
4
13
8
2
5
26
There can be many more rounds, and many more users.
I would like to pull the top 3 user scores from each round. My select statement at the moment looks like this:
select `scores`.`score`, `users`.`username`, `scores`.`roundID`
FROM `scores`
INNER JOIN `users` on `users`.`user_id` = `scores`.`userID`
ORDER BY `scores`.`score` DESC LIMIT 3;
However, this returns a result like so:
score
username
roundID
39
joey
2
26
bubba
2
25
george
1
when what I want is the top 3 scores per round:
score
username
roundID
25
george
1
14
bubba
1
12
joey
1
39
george
2
26
homey
2
23
joey
2
How do I select the top 3 scores in each round so my result mirrors the table immediately above?
You would do this like:
select score, username, roundID
from (
select
score, userID, roundID,
rank() over (partition by roundID order by score desc) score_rank
from score
) ranked_scores
inner join users on users.user_id = ranked_scores.userID
where score_rank <= 3
order by roundID, score, username

Sql join 4 tables count rows

I have 4 tables in similar form. Structures of these tables are like:
id team_id position_id country_id
1 1 1 3
2 1 1 3
3 2 2 3
4 3 3 3
I can count rows of one table with:
SELECT count(position_id) as count1, position_id
FROM players1
where country_id = 3
group by position_id;
Getting result as:
position_id count1
1 54
2 41
3 39
4 32
I want join 4 tables and want to get a result like:
position_id count1 count2 count3 count4
1 54 42 51 61
2 41 40 49 59
3 39 29 44 50
4 32 21 37 47
Can you help me write this sql?
As I have understand you question. Execute this Mysql query.
SELECT
d1.position_id AS Positions_Id,
d1.count1 AS count1,
d2.count1 AS count2,
d3.count1 AS count3,
d4.count1 AS count4
FROM (
SELECT position_id, COUNT(position_id) AS count1
FROM players1
WHERE country_id=3
GROUP BY position_id) AS d1
LEFT JOIN (
SELECT position_id, COUNT(position_id) AS count1
FROM players2
WHERE country_id=3
GROUP BY position_id
) AS d2 ON d2.position_id = d1.position_id
LEFT JOIN (
SELECT position_id, COUNT(position_id) AS count1
FROM players3
WHERE country_id=3
GROUP BY position_id
) AS d3 ON d3.position_id = d1.position_id
LEFT JOIN (
SELECT position_id, COUNT(position_id) AS count1
FROM players4
WHERE country_id=3
GROUP BY position_id
) AS d4 ON d4.position_id = d1.position_id

mysql query: how to

here's my (simplified) table structure:
table: category_main
id name
-------------
1 food
2 vegetable
table category_sub
id id_catmain name
---------------------
10 1 cake
11 1 chocolate
12 1 burger
13 2 apple
14 2 banana
table images
id id_catsub filename views
-------------------------------------
1 10 cake1.jpg 11
2 10 cake2.jpg 24
3 10 cake3.jpg 65
4 11 chocolate1.jpg 31
5 11 chocolate2.jpg 62
6 11 chocolate3.jpg 32
7 11 chocolate4.jpg 58
8 12 burger1.jpg 23
9 12 burger2.jpg 43
10 12 burger3.jpg 76
11 13 apple1.jpg 29
11 13 apple2.jpg 67
11 14 banana1.jpg 78
desired output:
id name total_views
----------------------------
1 food 425
2 vegetable 174
as you can see i want to get the total views for each main category.
currently i'm running a loop for each subcategory but there must be an easier and faster way :/
thanks
Double LEFT JOIN + aggregation will do the job.
SELECT cm.id, cm.name, sum(images.views) as views
FROM category_main as cm
LEFT JOIN category_sub as cs ON cs.id_catmain = cm.id
LEFT JOIN images ON images.id_carsub = cs.id
GROUP BY cm.id
ORDER BY views DESC;
LEFT JOIN (instead of JOIN) will make you sure that you have all categories listed even if there's no subcategory or image in it. If you don't want empty categories to be listed, then use JOIN.
SELECT c.id AS id, c.name AS name, sum(i.views) AS total_views
FROM category_main c, category_sub s, images i
WHERE c.id=s.id_catmain and s.id=i.id_catsub
GROUP BY c.id,c.name;
simply join the three tables, and then you can sum the views grouped by the id's:
select cm.id, cm.name, sum(i.views) as total_views from
category_main as cm inner join category_sub as cs on cm.id = cs.id_catmain
inner join cs.id = i.id_catsub group by cm.id

How to get RUNNING TOTAL for DATES- ORDER dates in ASC RANK

Imagine you have a members with distinct member_ids and dates of service
you now need to order the dates of service in ascending order and return the order of these dates in another column (date_count). the final result will look like this:
memberid name date date_count
122 matt 2/8/12 1
122 matt 3/9/13 2
122 matt 5/2/14 3
120 luke 11/15/11 1
120 luke 12/28/14 2
100 john 1/12/10 1
100 john 3/2/12 2
100 john 5/30/12 3
150 ore 5/8/14 1
150 ore 9/9/14 2
here is the query that works but does not return the date_count in ranking (1,2,3) order. This instead returns the same number for date_count, not sure why the num
memberid name date_count
122 matt 3
122 matt 3
122 matt 3
120 luke 5
120 luke 5
120 luke 5
100 john 6
100 john 6
150 ore 2
150 ore 2
SELECT A.MEMBERID, A.NAME,A.DATE, COUNT(B.DATE) AS DATE_COUNT FROM #WCV_COUNTS A
INNER JOIN #WCV_COUNTS B
ON A.MEMBERID <= B.MEMBERID
AND A.MEMBERID= B.MEMBERID
GROUP BY A.MEMBERID, A.NAME, A.DATE
ORDER BY A.MEMBERID
Thanks for help in advance!
Use ROW_NUMBER()
SELECT memberid, name, date,
ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY date) AS date_count
FROM #WCV_COUNTS
ORDER BY memberid, date