I have the following query
SELECT count
FROM (
SELECT count(id) as count FROM listens
WHERE user='None'
UNION
SELECT count(id) as count FROM listens
WHERE user!='None'
) as details
which returns
count
36793
112755
I would like to perform the division on the two values (e.g. 36793 / 112755) so that the output from my query is
count
0.3263092546
You don't need union at all! Here is a much simpler way of writing the query:
SELECT sum(user = 'None') / sum(user <> 'None')
FROM listens;
MySQL treats a boolean expression as a number in a numeric context, with 0 for false and 1 for true. The above counts the number of values that match the conditions.
If you want to be verbose or to be compatible with other dialects of SQL, you can do:
SELECT (sum(case when user = 'None' then 1 else 0 end) /
sum(case when user <> 'None' then 1 end)
) as ratio
FROM listens;
I don't see a particular advantage to the verbosity if you are using MySQL, but the logic is equivalent.
Related
Is it possible to write a SELECT query that displays the name of each record once and the count of how many instances of that record there are for certain criteria?
For example, If I have a table with the following records:
How can I get the SELECT query to display the following:
You can use conditional aggregation:
select customer,
sum( status = 'Disposed' ) as num_disposed,
sum( status = 'Transported' ) as num_transported
from t
group by customer;
MySQL treats boolean expressions like integers in a numeric context, with 0 for false and 1 for true. So, just adding up the boolean is a simple way to count the number of rows that match the condition.
you can use a group by on case ansum for case
select customer, sum(case when status ='disposed' then 1 else 0 end) count_disposed
sum(case when status ='trasposed' then 1 else 0 end) count_trasposed
from my_table
group by customer
I have been struggling with something in MySQL.
Here is my problem:
I have a query returning a list of dates, here it is:
SELECT MIN(act_date) AS d FROM acts WHERE act_type_id = 'PA' GROUP BY contact_id;
Now, I want to randomly assign values from this list to each row of another query so that the distribution of dates stay the same. Then, my higher level query will compute things based on that dates. Here is the higher level query:
SELECT
a1.contact_id,
DATEDIFF(d, MAX(a1.act_date)) / 365 AS recency,
COUNT(a1.amount) AS frequency,
AVG(a1.amount) AS avg_amount,
MAX(a1.amount) AS max_amount,
DATEDIFF(d, MIN(a1.act_date)) / 365 AS seniority,
COUNT(CASE WHEN payment_method_id = 'CH' THEN 1 ELSE NULL END) AS nb_ch,
0 AS switched
FROM
acts a1
WHERE
YEAR(act_date) >= 1991
GROUP BY 1
HAVING SUM(CASE WHEN act_type_id = 'PA' THEN 1 ELSE 0 END) = 0;
I don't really know if it is possible to do that with SQL. Should I rather import my data in R at first in order to do it?
Thank you all very much for your help!
Some notes:
A subquery that returns a scalar can be used in the SELECT list.
The MySQL RAND() function returns a pseudo-random value.
We can use an expression in an ORDER BY clause.
...
For small sets, or where performance isn't a concern, we can do something like this:
SELECT ...
, 0 AS switched
, ( SELECT MIN(r.act_date)
FROM acts r
WHERE r.act_type_id = 'PA'
GROUP BY r.contact_id
ORDER BY RAND()
LIMIT 1
) AS act_date_min_by_contact_id_rand
FROM acts a1
...
This is my first post, so any general corrections to format/content are also welcome. I'm relatively new to SQL.
Say I have a database which collects test results from an classification evaluation. I know what the expected outcome is for each test. I also have a column indicating whether the test was successful, ie the expected value returned matched the expected value. It looks something like this:
Expected_Result Result Success
A A True
A B False
B B True
A A True
B A False
I know I can return the total occurrences of each expected type withSELECT Expected_Result, COUNT(Expected_Result) FROM Evaluation_Results GROUP BY Expected_Result.
I know how to count the number of false detections for a specific expected outcome with SELECT COUNT(*) FROM Evaluation_Results WHERE Success = 'True' AND Expected_Result = 'A'
Where I'm struggling is combining the two. I would like the query to return a list of all distinct expected results, the total of each, the count of successful results, and the percentage of the total, like so:
Expected_Result Total Num_Successful Success_Rate
A 3 2 66.67
B 2 1 50.00
You could use a CASE expression to perform a condition check during aggregation. A case statement identifies a conditional outcome. For instance you could use:
select evaluation_result
, count(*) AS total
, sum(case when success='true' and result='a' then 1 else 0 end) AS num_successful
, sum(case when success='true' and result='a' then 1 else 0 end)/count(*) AS success_rate
from evaluation_results group by evaluation_result;
Basically what's happening there is you're taking a count(*) of all grades, a sum() of a 1 or 0 based on a conditional outcome, then performing the ratio math. There's no need for a join here. The CASE Expression is a powerful conditional statement which can be used in so many diverse ways.
Or for a more flexible solution have a look at this:
select evaluation_result
, count(*) AS total
, sum(case when success='true' and result=evaluation_result then 1 else 0 end) AS num_successful
, sum(case when success='true' and result=evaluation_result then 1 else 0 end)/count(*) AS success_rate
from evaluation_results group by evaluation_result;
You can use self join if table is same like.
SELECT distinct e.Expected_Result, COUNT(Expected_Result), sum(e1.columns name), avg(e1.column name)
FROM Evaluation_Results e
left join Evaluation_Results e1 on e1.col=e.col
GROUP BY e.Expected_Result
Use this simple Query and check for the result..
select Expected_Result, count(Expected_Result) Total,
sum(IF ('True' = Success, 1, 0) ) Num_Successful,
avg(IF ('True' = Success, 1, 0 )) Success_Rate
from Evaluation_Results group by Expected_Result
I have a mysql table(tbl_subscriptiondetails) like the above.Here the last column i.e
'test_status' could have possible values C,S & Y only.
Using a single query i would like to fetch data in the manner
as shown below
But the query that i'm using gives me undesired results.My query is
SELECT pkg_name,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='C' AND mem_id=3) AS completed,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='S' AND mem_id=3) AS started,
(SELECT COUNT(*) FROM tbl_subscriptiondetails WHERE test_status='Y' AND mem_id=3) AS remaining
FROM tbl_subscriptiondetails
WHERE mem_id=3
GROUP BY pkg_name
and the result is
Please advise what is wrong. Thanks in advance.
You are running a subquery for each count, instead of counting as part of the main query. Therefore, your filter conditions aren't behaving as you expect them to. You can change it like so, to do the conditional count:
SELECT pkg_name,
SUM( case when test_status='C' then 1 else 0 end) AS completed,
SUM( case when test_status='S' then 1 else 0 end) AS started,
SUM( case when test_status='Y' then 1 else 0 end) AS remaining
FROM tbl
WHERE mem_id = 3
GROUP BY pkg_name
Demo
I have a table tasks with a status column The value of status can either be 0,1 or 2.
I need to implement the following logic:
If any value in status is 0 then the answer is 0.
If all values are 2 then the result is 2.
Otherwise the result is one.
Right now I'm doing this with 3 queries.
a) SELECT status FROM tasks
b) SELECT status FROM tasks WHERE status = 2;
c) SELECT status FROM tasks WHERE status = 0
So a) is for getting the total number of rows. Then I compare that to the number of rows given by b). If the match then the answer is 2. If they don't I do query c). If it is non-empty the answer is 0 otherwise the answer is 1.
Is there any way to write a single query for this? Or is there a better way of doing it?
You can do it using conditional aggregation:
SELECT CASE
WHEN s0 >= 1 THEN 0
WHEN sAll = s2 THEN 2
ELSE 1
END
FROM (
SELECT COUNT(*) AS sAll,
COUNT(CASE WHEN status = 0 THEN 1 END) AS s0,
COUNT(CASE WHEN status = 2 THEN 1 END) AS s2
FROM tasks ) t
The sub-query performs all counts required to apply your business logic. The outer query simply uses this info, to produce the required result.
It's a bit unclear from your description whether the first condition in the CASE takes precedence over the second. If not, then just switch the position of the two WHENs.
Try:
SELECT MIN(status) FROM tasks;
- since when all status values are 2, the minimum will be 2, when any value is 0 then the minimum will be 0 and otherwise the minimum wll be 1.
Use following
SELECT (case
when ((SELECT count(*) FROM tasks WHERE status = 0)>0) then 0
when ((SELECT count(*) FROM tasks WHERE status = 2)=(SELECT count(*) FROM tasks)) then 2
else 1 end) AS countOfStatus