MySQL Count single row based on 3 different criteria - mysql

I want to return an associative array based on a mySQL query such that the query results in 3 columns which are a count of a single set of data in 3 different ways. My best solution is a bit unweildly and I'm hoping there's a better way as there are some irrelevant complexities not shown below. Specifically I have a user table with a user number, their gender, and a place - the place being the dynamic variable which needs to be bound into the query later (in this instance I'm looking for place = 1). The basic table looks like this:
user gender place
1 m 1
2 m 2
3 f 1
4 m 1
5 f 2
I'd like to return 3 columns which are total, total male, total female at place 1.
My first attempt returns 3 rows with the right values, but as they are rows I can't access them cleanly using an associative array:
SELECT COUNT(DISTINCT user) as total FROM users WHERE place=1
UNION ALL
SELECT COUNT(DISTINCT id_customer) as male FROM users
WHERE gender = 'm' AND place=1
UNION ALL
SELECT COUNT(DISTINCT id_customer) as female FROM users
WHERE gender = 'f' AND place=1
My second attempt gives me the correct result but seems a bit verbose as I'll have to bind the place variable 3 times - is there a better way to do this?
SELECT total, male, female FROM
(SELECT COUNT(DISTINCT user) as total FROM users
WHERE place=1
) as total
INNER JOIN
(SELECT COUNT(DISTINCT user) as male FROM users
WHERE place=1 AND gender='m') as male
INNER JOIN
(SELECT COUNT(DISTINCT user) as female FROM users
WHERE place=1 AND gender='f') as female

Do you need the DISTINCT part? or is "user" field unique (primary key or otherwise)?
I prepared both versions in http://sqlfiddle.com/#!9/928fa/7
If user is unique, then this should be enough:
SELECT count(1), sum(gender='m'), sum(gender='f')
FROM users
WHERE place=1;

Related

Possible to count number of occurrences in a "group" in MySQL?

Sorry if the title is misleading, I don't really know the terminology for what I want to accomplish. But let's consider this table:
CREATE TABLE entries (
id INT NOT NULL,
number INT NOT NULL
);
Let's say it contains four numbers associated with each id, like this:
id number
1 0
1 9
1 17
1 11
2 5
2 8
2 9
2 0
.
.
.
Is it possible, with a SQL-query only, to count the numbers of matches for any two given numbers (tuples) associated with a id?
Let's say I want to count the number of occurrences of number 0 and 9 that is associated with a unique id. In the sample data above 0 and 9 does occur two times (one time where id=1 and one time where id=2). I can't think of how to write a SQL-query that solves this. Is it possible? Maybe my table structure is wrong, but that's how my data is organized right now.
I have tried sub-queries, unions, joins and everything else, but haven't found a way yet.
You can use GROUP BY and HAVING clauses:
SELECT COUNT(s.id)
FROM(
SELECT t.id
FROM YourTable t
WHERE t.number in(0,9)
GROUP BY t.id
HAVING COUNT(distinct t.number) = 2) s
Or with EXISTS():
SELECT COUNT(distinct t.id)
FROM YourTable t
WHERE EXISTS(SELECT 1 FROM YourTable s
WHERE t.id = s.id and s.id IN(0,9)
HAVING COUNT(distinct s.number) = 2)

MySQL to count total number of specimens

I have to get total number of specimens in the database.
Table1:
There are 5 specimens as shown in the figure: user 1 has 2, user 2 has 2 and user 3 has 1 number of specimens (users are asked to type a word a number of times and each word is called here a specimen,e.g., cat, bird etc).
I tried following query:
Select count(distinct userId) from Table1 group by userId
It shows user ID wise total specimens. But what I need is total number of specimens inclusive of all users,i.e, 5.
You can use select distinct with multiple columns:
How do I (or can I) SELECT DISTINCT on multiple columns?
Then you can apply count(*) to the result:
select count(*) from (select distinct userId, specimen from Table1);
Note that it works not with MySQL only but with other dialects as well (including SQLite).

SQL: Select count and percentage with conditions

I have two tables
User
id_user|INT
company | varchar
and
Log
log_id|int
id_user|int
I need to return the company, the total number of users per company, and the percentage of users that have atleast 3 logs
I can run this query to get the company and counts
select company, count (*) as 'Count'
from user
group by company
which returns this
Apple| 7
Google| 6
But I am having trouble figuring out how to then return an extra column that displays the percentage of those users that have at least 3 logs. For example,
If there were 2 users who had more than 3 logs from Apple and one user from Google who had more than 3 logs, the answer would look like this:
Apple| 7| 29% (because 2/7=~29%)
Google| 6| 17% (because 1/7=~17%)
I figured this requires the use of windows function or some type of correlated subquery but I'm having issues accurately obtaining the correct percentage.
Any help would be greatly appreciated. (using SQL server 2008)
I was actually able to do this without using window functions, though there is probably a version which would use them. First, I aggregate the number of logs per user in a CTE. Then, I join the user table to this, using conditional aggregation to count the number of users per company having 3 logs or more.
WITH cte AS (
SELECT id_user, COUNT(*) AS cnt
FROM Log
GROUP BY id_user
)
SELECT
u.company,
COUNT(DISTINCT u.id_user) AS total_users,
100.0 * SUM(CASE WHEN c.cnt >= 3 THEN 1 ELSE 0 END) /
COUNT(DISTINCT u.id_user) AS log_3_users
FROM [User] u
LEFT JOIN cte c
ON u.id_user = c.id_user
GROUP BY
u.company;
Demo
Note that in the demo I just have some dummy data, where 1 out of 3 Google users has 3 or more logs, and 1 out of 2 Microsoft employees has 3 or more logs.

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 for weighted voting - how to calculate with values assigned to different columns

I have a voting application that writes values to a mysql db table. It is a preference/weighted voting system so people choose a first option, second option, and third option. These all go into separate fields in the table. I'm looking for a way to write a query that will assign numerical values to the responses (3 for a first response, 2 for a second, 1 for a first) and then display the value with the summed score. I've been able to do this for total number of votes
select count(name) as votes,name
from (select 1st_option as name from votes
union all
select 2nd_option from votes
union all
select 3rd_option from votes) as tbl
group by name
having count(name) > 0
order by 1 desc;
but haven't quite figured out how to assign values to response in each column and then pull them together. Any help is much appreciated. Thanks!
You could do something like this:
select sum(score) as votes,name
from (select 1st_option as name, 3 as score from votes
union all
select 2nd_option as name, 2 as score from votes
union all
select 3rd_option as name, 1 as score from votes) as tbl
group by name;