How te get a percentage of rows in mysql - mysql

I have a table like this
user result
john +
mike -
john -
rita +
I want to get the percentage of - grouped by user. So for my example the result must be:
user %min
john 50%
mike 100%
rita 0%
Is that possible in mysql to create such a query?

Just use conditional aggregation. Here is a simple method:
select user, avg(result = '-') as percent_min
from t
group by user;
This will give the result as a value between 0 and 1, which can then be formatted as you desire.

Gordon's answer implies a database platform that implicitly casts a Boolean TRUE to 1 and a Boolean FALSE to 0. Which is not prescribed by the standard. Should you run into an error going something like "Function avg(boolean) does not exist", try a CASE expression:
WITH tb (usr,result) AS (
SELECT 'john','+'
UNION ALL SELECT 'mike','-'
UNION ALL SELECT 'john','-'
UNION ALL SELECT 'rita','+'
)
SELECT
usr
, AVG(CASE result WHEN '-' THEN 100 ELSE 0 END) AS percent_min
FROM tb
GROUP BY usr
ORDER BY usr;
Happy playing -
Marco

Related

To get total count based on condition

I am struggling to get the count of a particular person. As I am new to tableau I don't know how to write the condition for this query.
SELECT COUNT(*) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 AND
IsAccepted = 1
Generate a calculated field as:
Calculation1: IF ExpertID=3 AND IsAccepted = 1 THEN 1 ELSE 0 END
Then, place this field on a shelf (row, columns, etc.) and select Measure (Sum).
You can use LOD (Level of Detail) like so:
{ FIXED [ExpertID]: SUM(IF [IsAccepted]= 1 THEN 1 ELSE 0 END) }
This will give you aggregated values for each user.
For more information on LOD, please follow official Tableau help link here
SELECT COUNT(ExpertID),COUNT(IsAccepted ) as cnt
FROM
Expert_CollaborationsRequests
WHERE
ExpertID=3 OR
IsAccepted = 1

MySQL - Take Specific row being a value NULL or max, not just column

I'm searching how to make a select with 2-3 columns and take the results with the parameter in one column as NULL, otherwise if there is no NULL for a username, take the max date.
My problem is that in the results, the ipaddr is from the max stoptime row, if there is no NULL row i get the ipaddr correctly
Is important for me for can search by user.
Lets take a look to my database format:
username stoptime ipaddr
peter 2012-10-16 00:00:00 1.1.1.1
obama 2014-03-12 00:00:00 1.1.1.2
peter 2013-10-16 00:00:00 1.1.1.3
obama NULL 1.1.1.4
When i launch:
SELECT username,case when MAX(stoptime is NULL)=0 then max(stoptime) end as stoptime,ipaddr
FROM tb
WHERE username LIKE "%OBAM%" group by username;
In this example i expect to take from my query this results:
obama NULL 1.1.1.4
Instead this i take this:
obama NULL 1.1.1.2
Thanks!
You are using group by incorrectly. In particular, you have columns in the select that are not in the group by. MySQL specifically discourages this (see here).
The simplest way to do what you want is:
SELECT username,
(case when max(stoptime is null) = 0
then max(stoptime)
end) as stoptime,
substring_index(group_concat(ipaddr order by (stoptime is null) desc, stoptime desc), ',', 1) as ipaddr
FROM tb
WHERE username LIKE "%OBAM%"
group by username;
However, there are some limitations with this approach -- such as the size of the intermediate string for concatenation. There are other methods, but this works in many cases.
you helped me a lot, i had to make some changes, now i have to concatenate this query with some left joins thank you very much, this is my finnal query: just im afraid for the size of the intermediate string for concatenation, it can be with hundreds, probably with thousands of different results wich problem can i get if its too long? how much is too long?
SELECT username, coalesce(max(stoptime)) as lasstop,
substring_index(group_concat(ipaddr order by starttime desc), ',', 1) as ipaddr,
substring_index(group_concat(stoptime order by starttime desc), ',' ,1) as stopt,
CASE WHEN MAX(CASE WHEN stoptime IS NULL THEN 1 ELSE 0 END) = 0
THEN MAX(stoptime) END as x FROM tb WHERE username LIKE "%%" group by username;
Best regards.

query using SOME in mysql not giving expected results.?

Suppose I have a table :
start_range end_range
1 4
4 8
I want the result to be true if it is greater than any of the value of start_range and less than any of the corresponding end_range.
Eg.
value 2 should return true , as 2>1 and 2<4
but value 4 should return false in this case as 4>1 but 4<4 becomes false, as well as 4>4 becomes false for the second case.
I cannot use the query
SELECT Sumthing
FROM XYZ
WHERE value> SOME(start_range) AND value < SOME(end_range)
The problem with the above query is let say value = 4.
Now 4> SOME(start_range) will become true as 4>1. AND
4< SOME(end_range) will also become true as 4<8.
But in actual the comparison should be like (((4>1)AND(4<4)) OR ((4>4)AND(4<8))) . It should return false.
One more thing , the above table is not persistent , I have been creating it in a subquery.Thats why i have been using SOME.
if still my question isn't clear, mention in comments.
Assuming that xyz is your table:
select (count(*) > 0) as HasMatch
from xyz
where value > start_range and value < end_range;
I'm not sure why you are using some.
EDIT:
It occurs to me that you want to use subqueries, and xyz is not the table in question. Perhaps this is what you want:
select xyz.*
from xyz
where exists (select 1
from (<your query here>) t
where xyz.value > t.start_range and xyz.value < t.end_range
);
you can do something like this
SELECT CASE WHEN start_range<value and end_range>value
THEN 'true'
ELSE 'false'
END here_name_to_this_column(optional)
FROM table_name
tutorial link
select (count(*) > 0) as HasMatch
from (select IF(start_range<value and end_range>value, true, false ) as value
from XYZ having value =1) as MatchTable
DEMO

Counting total and true condition lines

How to count the number of lines in a table and the number of lines where a certain condition is true without resorting to subselects like this:
create table t (a integer);
insert into t (a) values (1), (2), (null);
select
(select count(*) from t) as total_lines,
(select count(*) from t where a = 1) as condition_true
;
total_lines | condition_true
-------------+----------------
3 | 1
select count(*) as total_lines, count(a = 1 or null) as condition_true
from t
;
total_lines | condition_true
-------------+----------------
3 | 1
It works because:
First while count(*) counts all lines regardless of anything, count(my_column) will count only those lines where my_column is not null:
select count(a) as total
from t
;
total
-------
2
Second (false or null) returns null so whenever my condition is not met it will return null and will not be counted by count(condition or null) which only counts not nulls.
Use SUM(condition)!
select
count(*) as total_lines,
sum(a = 1) as condition_true
from t
See it working here.
This works because in mysql, true is 1 and false is 0, so the sum() of a condition will add 1 when it's true and 0 when it's false - which effectively counts the number of times the condition is true.
Many people falsely believe you need a case statement, but you don't with mysql (you do with some other databases)
this can be easily done using a condition inside count. I don't know if its the optimized method of doing it but it gets the work done
you can do it as follows
select count(*) as total_lines, COUNT(CASE WHEN a = 1 THEN 1 END) as condition_true from t
you can check it here
sqlFiddle

Select multiple sums with MySQL query and display them in separate columns

Let's say I have a hypothetical table like so that records when some player in some game scores a point:
name points
------------
bob 10
mike 03
mike 04
bob 06
How would I get the sum of each player's scores and display them side by side in one query?
Total Points Table
bob mike
16 07
My (pseudo)-query is:
SELECT sum(points) as "Bob" WHERE name="bob",
sum(points) as "Mike" WHERE name="mike"
FROM score_table
You can pivot your data 'manually':
SELECT SUM(CASE WHEN name='bob' THEN points END) as bob,
SUM(CASE WHEN name='mike' THEN points END) as mike
FROM score_table
but this will not work if the list of your players is dynamic.
In pure sql:
SELECT
sum( (name = 'bob') * points) as Bob,
sum( (name = 'mike') * points) as Mike,
-- etc
FROM score_table;
This neat solution works because of mysql's booleans evaluating as 1 for true and 0 for false, allowing you to multiply truth of a test with a numeric column. I've used it lots of times for "pivots" and I like the brevity.
Are the player names all known up front? If so, you can do:
SELECT SUM(CASE WHEN name = 'bob' THEN points ELSE 0 END) AS bob,
SUM(CASE WHEN name = 'mike' THEN points ELSE 0 END) AS mike,
... so on for each player ...
FROM score_table
If you don't, you still might be able to use the same method, but you'd probably have to build the query dynamically. Basically, you'd SELECT DISTINCT name ..., then use that result set to build each of the CASE statements, then execute the result SQL.
This is called pivoting the table:
SELECT SUM(IF(name = "Bob", points, 0)) AS points_bob,
SUM(IF(name = "Mike", points, 0)) AS points_mike
FROM score_table
SELECT sum(points), name
FROM `table`
GROUP BY name
Or for the pivot
SELECT sum(if(name = 'mike',points,0)),
sum(if(name = 'bob',points,0))
FROM `table
you can use pivot function also for the same thing .. even by performance vise it is better option to use pivot for pivoting... (i am talking about oracle database)..
you can use following query for this as well..
-- (if you have only these two column in you table then it will be good to see output else for other additional column you will get null values)
select * from game_scores
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));
in this query you will get data very fast and you have to add or remove player name only one place
:)
if you have more then these two column in your table then you can use following query
WITH pivot_data AS (
SELECT points,name
FROM game_scores
)
SELECT *
FROM pivot_data
pivot (sum(points) for name in ('BOB' BOB, 'mike' MIKE));