How to count rows in MySQL using an IF statement? - mysql

I have a relatively simple question but I'm stuck with writing a proper SQL query to display the results that I need. I have a table which stores results from matches with columns indicating the IDs of the players that took part in the match, the winner and another boolean column which let's say indicates whether I want to include that match in the result or not. So the columns are:
player1_id | player2_id | winner_id | use
So winner_id is the value from one of the first two columns depending on which player won. If I want to count how many times a certain player won a game just using the rows where the use flag is up, I can easily do so with:
SELECT COUNT(*) AS total, winner_id
FROM table
WHERE use = 1
GROUP BY winner_id
ORDER BY total DESC
However, I also want to do the same count but for the players that lost their matches. In other words, I want to group not by the winner_id but by the loser id, which would be the value of either player1_id or player2_id depending on which one of them is different from the winner_id. Any clues on how to do that with a simple query that works?

You can do like this to count the loosers:
SELECT
COUNT(*) AS total,
IF(player1_id = winner_id, player2_id, player1_id) AS looser_id
FROM table
WHERE use = 1
GROUP BY looser_id
ORDER BY total DESC

Related

MySQL count select query with condition

I have a mysql table called Game which has two columns, Name and Score. I want to select only the Names whose scores have been atleast 100 and atleast twice. In the below example Ron and Mary will get selected. I am not sure how to write the select statement for this.
Game table
Use GROUP BY with a HAVING clause:
SELECT Name
FROM mytable
GROUP BY Name
HAVING COUNT(CASE WHEN Score >= 100 THEN 1 END) >= 2
HAVING clause checks for Name groups, having at least two records with Score >= 100.

Multiple counts and math operator in MySQL

I have two tables, one contains the results of a game (which game played and number of games won), the second lists how many selections they have gotten right for a given game (i.e % correct).
I need to make a single query to calculate the percentage of times a user has won for each game. Each user may have played a different number of games.
I've tried to do this using COUNT, but if I group the count function to determine the number of times a user has player I can then not get the total number of times the user has won. See fiddle..
http://sqlfiddle.com/#!2/defc3/1
UPDATE result, games_played
SET result.precentage_correct =
(
**SELECT (COUNT(gp.user_id)/COUNT(gp.user_id)*100)**
FROM games_played as gp
WHERE result.user_id = gp.user_id
AND gp.winner != 'n'
AND gp.game = 1
GROUP BY gp.user_id
)
WHERE games_played.user_id = result.user_id
So, somehow I need to have two different COUNT functions with a math operator
You could simply combine two queries, one that selects only winning records, and another that selects all queries. Once you have these two counts, you can select from them to calculate the ratio.
SELECT user_id, 100*SUM(n_win)/SUM(n_total) AS pct_win FROM
(SELECT user_id, COUNT(user_id) AS n_win,
NULL AS n_total
FROM games_played
WHERE winner != 'n'
AND game = 1
GROUP BY user_id
UNION SELECT user_id, NULL AS n_win,
COUNT(user_id) AS n_total
FROM games_played
WHERE game = 1
GROUP BY user_id
) AS counts
GROUP BY counts.user_id;
Note that to combine the queries, one field of either n_win or n_total will be NULL in each subquery. The query will yield:
USER_ID PCT_WIN
1 50
2 66.6667
3 50
4 100
The union of the two subqueries will have two records for each user, one record for which n_win is known, the other record will have the value for n_total. For the first two users, it would look like
USER_ID N_WIN N_TOTAL
1 1 NULL
2 2 NULL
1 NULL 2
2 NULL 3
The outer query selects from that union the user_id and n_win / n_total grouped by user_id, thus yielding 50.0% and 66.6%. I am using SUM because it allows me to collect the non-NULL value for each column for each user.

MySQL Query to find row duplicates based on condition with limit

I have two tables:
Members:
id username
Trips:
id member_id flag_status created
("YES" or "NO")
I can do a query like this:
SELECT
Trip.id, Trip.member_id, Trip.flag_status
FROM
trips Trip
WHERE
Trip.member_id = 1711
ORDER BY
Trip.created DESC
LIMIT
3
Which CAN give results like this:
id member_id flag_status
8 1711 YES
9 1711 YES
10 1711 YES
My goal is to know if the member's last three trips all had a flag_status = "YES", if any of the three != "YES", then I don't want it to count.
I also want to be able to remove the WHERE Trip.member_id = 1711 clause, and have it run for all my members, and give me the total number of members whose last 3 trips all have flag_status = "YES"
Any ideas?
Thanks!
http://sqlfiddle.com/#!2/28b2d
In that sqlfiddle, when the correct query i'm seeking runs, I should see results such as:
COUNT(Member.id)
2
The two members that should qualify are members 1 and 3. Member 5 fails because one of his trips has flag_status = "NO"
You could use GROUP_CONCAT function, to obtain a list of all of the status ordered by id in ascending order:
SELECT
member_id,
GROUP_CONCAT(flag_status ORDER BY id DESC) as status
FROM
trips
GROUP BY
member_id
HAVING
SUBSTRING_INDEX(status, ',', 3) NOT LIKE '%NO%'
and then using SUBSTRING_INDEX you can extract only the last three status flags, and exclude those that contains a NO. Please see fiddle here. I'm assuming that all of your rows are ordered by ID, but if you have a created date you should better use:
GROUP_CONCAT(flag_status ORDER BY created DESC) as status
as Raymond suggested. Then, you could also return just the count of the rows returned using something like:
SELECT COUNT(*)
FROM (
...the query above...
) as q
Although I like the simplicity of fthiella's solution, I just can't think of a solution that depends so much on data representation. In order not to depend on it you can do something like this:
SELECT COUNT(*) FROM (
SELECT member_id FROM (
SELECT
flag_status,
#flag_index := IF(member_id = #member, #flag_index + 1, 1) flag_index,
#member := member_id member_id
FROM trips, (SELECT #member := 0, #flag_index := 1) init
ORDER BY member_id, id DESC
) x
WHERE flag_index <= 3
GROUP BY member_id
HAVING SUM(flag_status = 'NO') = 0
) x
Fiddle here. Note I've slightly modified the fiddle to remove one of the users.
The process basically ranks the trips for each of the members based on their id desc and then only keeps the last 3 of them. Then it makes sure that none of the fetched trips has a NO in the flag_status. FInally all the matching meembers are counted.

Combining two MySQL queries from the same table

I have a table set up currently as such:
issue|total | series
-----|--------|---------
1 | 1 | Series A
2 | 2 | Series A
1 | 3 | Series B
3 | 4 | Series A
2 | 5 | Series B
1 | 6 | Series C
It tracks series (series), along with the issue number (issue) within each series. As well as that, I have a running total (total) of the entire number of entries in this table.
What I would like to do is combine two queries, the first used to locate the last issue number within a given series, the second to always locate the last total number within the table. Presumably the two queries I need to use are as follows, I just don't see how would be best to combine them into one select query:
To locate last issue of a given series:
SELECT issue FROM seriesTable WHERE series = 'Series A|Series B|Series C' ORDER BY issue DESC LIMIT 1
To locate total number of entries:
SELECT total FROM seriesTable ORDER BY total DESC LIMIT 1
So, if I wanted to reference the last issue of Series A and the total number of entries (3, 6), what would be the best way to do this? I've tried INNER JOIN and UNION neither of which seem to work, however I think I'm on the right track, just using the syntax incorrectly.
I guess the other alternative is to run the queries separately, add to an array and have PHP give me the result, however I would rather avoid this if possible.
Original answer is below, after clarification I have have another answer
You only need to cross join a single row result set with the total you're fater.
for series A
SELECT series, MAX(issue), total.total FROM seriesTable
JOIN (SELECT total FROM seriesTable ORDER BY total DESC LIMIT 1) total
WHERE series = 'Series A';
or for every series
SELECT series, MAX(issue), total.total FROM seriesTable
JOIN (SELECT total FROM seriesTable ORDER BY total DESC LIMIT 1) total
GROUP BY series;
sql fiddle
Original answer
So, to get "total for each series as of the last issue for that series" you need to self join and group by series to find the max issue, then use that as you join to extract the total.
select issue as current_issue, total, series from seriesTable
natural join (SELECT series,
max(issue) as issue
FROM seriesTable
group by series) max_issues;
sql fiddle
You just need the max issue for a particular series, and you also need the max total for the table.
I think this is what your looking for:
SELECT max(issue),
(SELECT max(total)
FROM seriesTable)
FROM seriesTable
WHERE series = 'Series A'

Determine total amount of top result returned

I would like to determine two things from a single query:
Most prevalent column in a table
The amount of times such column was located upon querying the table
Example Table:
user_id some_field
1 data
2 data
1 data
The above would return user_id # 1 as being the most prevalent in the table, and it would return (2) for the total amount of times that it was located in the table.
I have done my research and I came across two types of queries.
GROUP BY user_id ORDER BY COUNT(*) DESC
SUM
The problem is that I can't figure out how to use these two queries in conjunction with one another. For example, consider the following query which successfully returns the most prevalent column.
$top_user = "SELECT user_id FROM table_name GROUP BY user_id ORDER BY COUNT(*) DESC";
The above query returns "1" based on the example table shown above. Now, I would like to be able to return "2" for the total amount of times the user_id (1) was found in the table.
Is this by any chance possible?
Thanks,
Evan
You can include count(*) in the SELECT list:
SELECT user_id, count(*) as totaltimes from table_name
GROUP BY user_id ORDER BY count(*) DESC;
If you want only the first one:
SELECT user_id, count(*) as totaltimes from table_name
GROUP BY user_id ORDER BY count(*) DESC LIMIT 1;