Make a calculation with aliases in one (sub)query - mysql

I have a table with data and am trying to make the following calculation in a query: IDO / IDP * 100.
**TBL**
Name IDP IDO
ABC 123 231
DEF 124 NULL
GHI 125 NULL
JKL 126 342
KNM 127 NULL
I managed to count up all the values needed to make the calculation and gave each an alias. This is what I have so far, but the calculation part returns an error telling me the references are not supported.
SELECT
SUM(case when IDP is not null then 1 end) as Checked,
SUM(case when IDO is null then 1 end) as NotChecked,
(SELECT Checked / NotChecked) * 100 AS Result
FROM TBL
I've also tried with a subquery, but it results in the same error.
SELECT
SUM(case when IDP is not null then 1 end) as Checked,
SUM(case when IDO is null then 1 end) as NotChecked,
(
SELECT Checked / NotChecked * 100 AS Result FROM TBL
)
FROM TBL
What would be the right or a better way to do this?

I don't think you will be able to reference aliases created in a SELECT clause in that same SELECT clause.
As you probably know, you could just repeat the logic, like the following (although I assume the purpose of your question is to avoid writing the logic twice).
SELECT
SUM(case when IDP is not null then 1 end) as Checked,
SUM(case when IDO is null then 1 end) as NotChecked,
(SUM(case when IDP is not null then 1 end) / SUM(case when IDO is null then 1 end)) * 100 AS Result
FROM TBL
A subquery version, where you don't repeat the logic, would be the following. Note that the aliases are created in the subquery so the outer query has no trouble referencing them.
SELECT
Checked, NotChecked, (Checked / NotChecked) * 100 as Result
FROM
(
SELECT
SUM(case when IDP is not null then 1 end) as Checked,
SUM(case when IDO is null then 1 end) as NotChecked
FROM TBL
) tt
Since you don't seem to be summing, just counting null/non-null values, I personally find the sum/case statements a bit confusing and might prefer something like this:
SELECT
Checked, NotChecked, (Checked / NotChecked) * 100 as Result
FROM
(
SELECT
count(IDP) as Checked,
count(*)-count(IDO) as NotChecked
FROM TBL
) tt

Related

Display sum of each element in a column using sql?

I have simple data from database looks like this
ID sid targetbuttonname
1 ab23sve Yes
2 ab23sve Yes
3 ab23sve Yes
4 ab23sve Yes
5 z32b2367 no
6 zb23sve no
7 pb23sve Yes
I want to display the sum of session, the sum of yes, the sum of no using sql;
eg sum of yes should be 5 etc
I tried something like this
select sum(sid), count(targetbuttoname) as yes, count(targetbuttoname) as no from events
What is the right way to display what I want?
Presumably, you want to count these things. So, I would guess:
select count(*) as num_rows,
count(distinct sid) as num_sessions,
sum( targetbuttonname = 'yes' ) as num_yes,
sum( targetbuttonname = 'no' ) as num_no
from events;
Here is a db<>fiddle.
if you want to count number of yes and no then you can use case when
select sum(case when targetbuttoname='yes' then 1 else 0 end) as yes,
sum(case when targetbuttoname='no' then 1 else 0 end) as no from events

Multiple conditional counts in the same SQL sentence [duplicate]

This question already has answers here:
multiple query same table but in different columns mysql
(4 answers)
Closed 4 years ago.
The goal is to get the progress on a list of tasks considering the status of each tasks, ruling out invalid tasks.
Currently, I managed to do this at a very expensive hit on performance and would like to know if it's possible to achieve the same result in one SQL sentence or at least find a more optimized way.
SELECT COUNT(`id`) AS `status` FROM `task` WHERE `status` = 'done'
UNION
SELECT COUNT(`id`) AS `status` FROM `task` WHERE `status` = 'pending';
The above query results in 2 rows, I can sum them up and get the total of 5 which is correct, first row is count of done tasks: from there is easy to get 3/5 or 60% done
status
------
3
2
I know this example is very specific, I tried this query but encountered some problems. Is about the grouping? or I'm completely wrong here?
SELECT
COUNT(CASE WHEN `status` = 'done' THEN 1 ELSE 0 END) AS `done`,
COUNT(CASE WHEN `status` = 'pending' THEN 1 ELSE 0 END) AS `pending`
FROM `task`
GROUP BY `status`;
The above query results in 2 columns and 3 repeated rows:
done pending
---------------
3 3
1 1
2 2
At this example table I'm looking at 3 out of 5 valid tasks or 60% completed.
name status
------------------
task 1 done
task 2 done
task 3 pending
task 4 done
task 5 invalid
task 6 pending
Thanks for any help!
You were counting the false condition as well with else 0. Eliminating it would default to null for a comparison that is false and wouldn't be counted.
SELECT
COUNT(CASE WHEN `status` = 'done' THEN 1 END) AS `done`,
COUNT(CASE WHEN `status` = 'pending' THEN 1 END) AS `pending`
FROM `task`
WHERE `status` in ('done','pending')
Or this can be simplified to
SELECT
SUM(`status` = 'done') AS `done`,
SUM(`status` = 'pending') AS `pending`
FROM `task`
WHERE `status` in ('done','pending')

Calculating acceptance_ratio with LEFT JOIN and SELF JOIN and aggregate function

Trying to calculate daily acceptance ratios from the 'connecting' table which has 4 fields with sample values:
date action sender_id recipient_id
'2017-01-05', 'request_link', 'frank', 'joe'
'2017-01-06', 'request_link', 'sally', 'ann'
'2017-01-07', 'request_link', 'bill', 'ted'
'2017-01-07', 'accept_link', 'joe', 'frank'
'2017-01-06', 'accept_link', 'ann', 'sally'
'2017-01-06', 'accept_link', 'ted', 'bill'
Because there are 0 accepts and 1 request on 01-05, its daily acceptance ratio should be 0/1 = 0. Similarly, the ratio for 01-06 should be 2/1, and it should be 1/1 for 01-07.
It is important however that each accept_link has a corresponding request_link where the sender_id of the request_link = the recipient_id of the accept_link (and vice versa). So here a self-join is required I believe to ensure that Joe accepts Frank's request, regardless of the date.
How can the below query be corrected so that the aggregation works correctly while retaining the required join conditions? Will the query calculate correctly as is if the two WHERE conditions are removed, or are they necessary?
SELECT f1.date,
SUM(CASE WHEN f2.action = 'accept_link' THEN 1 ELSE 0 END) /
SUM(CASE WHEN f2.action = 'request_link' THEN 1 ELSE 0 END) AS acceptance_ratio
FROM connecting f1
LEFT JOIN connecting f2
ON f1.sender_id = f2.recipient_id
LEFT JOIN connecting f2
ON f1.recipient_id = f2.sender_id
WHERE f1.action = 'request_link'
AND f2.action = 'accept_link'
GROUP BY f1.date
ORDER BY f1.date ASC
Expected output should look something like:
date acceptance_ratio
'2017-01-05' 0.0000
'2017-01-06' 2.0000
'2017-01-07' 1.0000
Thanks in advance.
Once again, I don't think you need to be using a self join here. Instead, just use conditional aggregation over the entire table, and count the number of requests and accepts which happened on each day:
SELECT t.date,
CASE WHEN t.num_requests = 0
THEN 'No requests available'
ELSE CAST(t.num_accepts / t.num_requests AS CHAR(50))
END AS acceptance_ratio
FROM
(
SELECT c1.date,
SUM(CASE WHEN c1.action = 'accept_link' AND c2.action IS NOT NULL
THEN 1 ELSE 0 END) AS num_accepts,
SUM(CASE WHEN c1.action = 'request_link' THEN 1 ELSE 0 END) AS num_requests
FROM connecting c1
LEFT JOIN connecting c2
ON c1.action = 'accept_link' AND
c2.action = 'request_link' AND
c1.sender_id = c2.recipient_id AND
c2.recipient_id = c1.sender_id
GROUP BY c1.date
) t
ORDER BY t.date
Note here that I use a CASE expression to handle divide by zero, which could occur should a certain day no requests. I also assume here that the same invitation will not be sent out more than once.

SQL query count = 0/null

I have the following MySql table with ~19000 entries like this:
ID USER FIELD1 FIELD2 SOMEINT ERROR
1 name1 null null null missing...
2 name1 value1 value2 3 validated!
3 name1 value3 wrongvalue1 null syntax
4 name2 wrongvalue2 value4 null syntax
etc...................................................................
I would like to get a list like this:
USER totalEntries totalValid totalMissing totalSyntax
name1 3 1 1 1
name2 1 0 0 1
etc...................................................................
I have a query for every column like this:
select user, count(user) valid from table where
someint is not null group by user limit 0, 20000;
(total valid entries)
select user, count(*) totalEntries from table group by user
limit 0, 20000; (total entries)
select user, count(*) totalMissing from table where field1 is null or
field2 is null group by user limit 0, 20000; (total Missing entrie)
select user, count(*) syntax from table where error like 'syntax%'
group by user limit 0, 20000 (syntaxerror entries)
The problem is that "group by" does not list the count(...) entries as
USER valid
...
name3 0
So the 4 query results do not have the same rowcount. How can I solve this Problem?
You are trying to do this:
SELECT user, COUNT(*) as totalEntries,
SUM(CASE WHEN someint IS NOT NULL THEN 1 ELSE 0 END),
SUM(CASE WHEN field1 IS NULL OR field2 IS NULL THEN 1 ELSE 0 END),
SUM(CASE WHEN error LIKE 'syntax%' THEN 1 ELSE 0 END)
FROM SomeTable
GROUP by user
User Name
Number of entries of the user
Number of entries of entries with some int different of NULL
Number of entries where Error ismissing`
Number of entries where ERROR is syntax
PD: Maybe you want to add the LIMIT 0,20000 at the end of the query. I didn't do that because I didn't get the purpose.

counting null data in MySQL

let say i have one table, which have data like:
name status
bob single
bob single
jane null
tina null
shane married
i want if status "single or data null" it means single. so if data empty script can read it as single and can count together.
so i can show result like:
Single Married
3 1
i have tried with this and it doesnt work:
SELECT SUM(IF(status='single',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
Use:
SELECT SUM(CASE WHEN x.status = 'single' OR x.status IS NULL THEN 1 ELSE 0 END) AS single,
SUM(CASE WHEN x.status = 'married' THEN 1 ELSE 0 END) AS married
FROM (SELECT DISTINCT
t.name,
t.status
FROM YOUR_TABLE t) x
If you know there are only 'single', 'married', and null as options, this will work:
SELECT SUM(IF(status!='married',1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
Otherwise try
SELECT SUM(IF(status='single' OR status is null,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table
SELECT SUM(IF(status='single' OR status IS NULL,1,0)) AS Single,
SUM(IF(status='married',1,0)) AS Married
FROM table