MySQL calculated column based on 2 conditions - mysql

I'm trying to calculate a basic 'attendance' report from a table of logs. My logs table appears like this:
TABLE logs
id | date | log |
------------------------|
123 | 2018-01-01 | 1234 |
123 | 2018-01-02 | | // Missed log
123 | 2018-01-03 | 5678 |
456 | 2018-01-01 | 5678 |
456 | 2018-01-02 | 1234 |
456 | 2018-01-03 | 1234 |
So an empty entry results in a missed date.
The desired SELECT result would be this:
id | perc |
------------|
123 | 0.666 |
456 | 1 |
I've tried the following but I'm not sure where to go from here:
SELECT id, count(*) AS attended WHERE log IS NOT NULL GROUP BY id ORDER BY attended
which yeilds:
id | attended |
---------------|
123 | 2 |
456 | 3 |
This gets me part of the way there, but I'm not sure how I can add a missed column to that, and then calculate the percentage. I'll be joining the result to a 'users' table later on, so names can be associated with the logs ids. Any help would be appreciated!

CASE condition that is suggested in another answer is redundant here as COUNT always counting NOT NULL records only. As a result, you can simplify the query:
SELECT
id
, COUNT(log) AS attended
, COUNT(*) - COUNT(log) AS missed
, IF(COUNT(*) > 0, count(log) / COUNT(*), NULL) AS percentage
FROM
logs
GROUP BY
id
ORDER BY
attended
In addition, I've fixed percentage calculation as per OP.

"conditional aggregates" solve this, basically you place a case expression inside the count() function
SELECT
id
, count(case when log IS NOT NULL then 1 end) AS attended
, count(case when log IS NULL then 1 end) AS Missed
, case when count(case when log IS NOT NULL then 1 end) > 0 then
count(case when log IS NOT NULL then 1 end) / count(*)
else 0
end AS perc
GROUP BY id
ORDER BY attended
If you use count(*) than all rows are counted, but if you count a value that can be NULL then those NULLs are not counted.

Related

How to distribute a row into different row grouped by the value it has and date created?

I have a table consisting of result, name and created_at like :
id | name | result | created_at
1 | Sam | 1 | 2018-07-12 05:08:04
2 | Tam | 1 | 2018-07-12 06:08:04
3 | Qam | 0 | 2018-07-12 07:08:04
4 | Yam | 1 | 2018-09-12 04:08:04
5 | Xam | 0 | 2018-09-12 06:08:04
6 | Lam | 0 | 2018-11-12 07:08:04
(the 1 represents pass where as 0 represent fails) I want to group the data by created at date which displays the count of result success or failed in seperate colums like:
fail | pass | created_at
0 | 2 | 2018-07-12 05:08:04
1 | 1 | 2018-09-12 04:08:04
1 | 0 | 2018-11-12 07:08:04
I could count the value of just pass or fail with this query: select count(result) from call_history where result = 1 GROUP BY DATE(created_at), but wasn't able to provide double where clause for different rows.
You can use a case expression to return a non-null result only for successes/failures, and then use count, which skips nulls:
SELECT COUNT(CASE result WHEN 0 THEN 1 END) AS fail,
COUNT(CASE result WHEN 1 THEN 1 END) AS pass,
created_at
FROM call_history
GROUP BY created_at
I would write this as:
SELECT SUM(1 - result) as fail,
SUM(result as pass)
created_at
FROM call_history
GROUP BY created_at;

count amount of days user enter into db

I have a table of items similar to this:
id | desc | created | user
-----------------------------
1 | a... | 2015-05-23 | 1
2 | b... | 2015-05-23 | 1
3 | c... | 2015-06-23 | 1
4 | d... | 2015-07-23 | 2
5 | e... | 2015-07-23 | 1
I want to count the amount of days where the user submitted to the db. MY desired result from the above example would be:
User 1: 3
User 2: 1
Please try below query, I hope it helps.
select user, count(distinct date(created)) from table_name group by user;
SQLFiddle
SELECT COUNT(DISTINCT created) from items WHERE user=':user_id'
This is assuming your 'created' column only receives distinct daily values, if not, you would have to use trim functions.
select user,count(DISTINCT created) from tableName group by user;
Here is an explanation how COUNT(DISTINCT ) works.

How to display MYSQL query result column_1 is querying this year, column_2 is querying a year ago?

i want to display a query result like this:
| Who_was_born_this_year | Who_was_born_year_ago |
___________________________________________________
| x | y |
| x | y |
where x will display Name of people who born in this year and y will display Name of people who born a year ago
TABLE PEOPLE STRUCTURE:
ID people | ID Gender | Name | Birthday
_________________________________________
1 | 1 | John | 18-07-2015
2 | 1 | Stu | 12-01-2014
3 | 2 | Leslie | 10-03-2014
All date format is dd-mm-yyyy
How can i achieve this with a query?
Thank you
You can try this:
SELECT
IF (YEAR(CURDATE()) = YEAR(Birthday), Name, '') Who_was_born_this_year,
IF (YEAR(CURDATE())-1 = YEAR(Birthday), Name, '') Who_was_born_year_ago
From people
;
but you will receive something like:
| Who_was_born_this_year | Who_was_born_year_ago |
___________________________________________________
| John | |
| | Stu |
| | Leslie |
and i suppose that it's not exactly what you desire...
But it's the best in this situation, because we don't have key how we should bind data for this year and for last year...
Or:
SELECT
(
SELECT group_concat(Name)
FROM people
WHERE YEAR(CURDATE()) = YEAR(Birthday)
) Who_was_born_this_year,
(
SELECT group_concat(Name)
FROM people
WHERE YEAR(CURDATE())-1 = YEAR(Birthday)
) Who_was_born_year_ago
;
but in this case you will receive something like:
| Who_was_born_this_year | Who_was_born_year_ago |
___________________________________________________
| John | |
| | Stu,Leslie |
and i again suppose that it's not exactly what you desire...
I think that it's not the best idea to represent data in way you wish...
You can use following query this query may help you,
SELECT
(CASE YEAR(Birthday) WHEN YEAR(curdate()) THEN name ELSE NULL END) as Who_was_born_this_year,
(CASE YEAR(Birthday) WHEN YEAR(curdate() - interval 1 year) THEN name ELSE NULL END) as Who_was_born_year_ago
FROM people WHERE YEAR( Birthday )IN (YEAR(curdate() - interval 1 year),YEAR(curdate()));
you can also optimize this query by selecting curent year and previous year firstly

How to Exclude Mysql Group

I would like to know how to exclude a mysql group, i did research on here for some time but just dont make it right.
I tried
SELECT * FROM booking GROUP BY BookingId HAVING Status!="Cancellation"
which obviously doesn't work.
Example Database looks like this:
+----+-----------+--------------+
| id | BookingId | Status |
+----+-----------+--------------+
| 1 | 1 | Booked |
| 2 | 1 | Cancellation |
| 3 | 2 | Booked |
+----+-----------+--------------+
I would like to group them by BookingId and if one of the found entries got the Status Cancellation this group shouldnt show up, so from above just the id 3 would be seen.
You need to use aggregate functions like sum in a having clause
SELECT BookingId
FROM booking
GROUP BY BookingId
HAVING sum(Status = 'Cancellation') = 0

Select rows who's FIRST result is a specific value

I've got a custom written analytics system running and I'm trying to write a query that returns users who landed on a specific page as their first hit. The relevant parts of the table is setup as such, with some simple data:
pageviews Table
+----+---------------------+----------+-------------+
| id | time_in | users_id | articles_id |
+----+---------------------+----------+-------------+
| 0 | 2013-08-15 00:00:00 | 0 | 0 |
| 1 | 2013-08-16 00:00:00 | 0 | 1 |
| 2 | 2013-08-17 00:00:00 | 1 | 1 |
| 3 | 2013-08-18 00:00:00 | 1 | 0 |
| 4 | 2013-08-19 00:00:00 | 1 | 1 |
| 5 | 2013-08-20 00:00:00 | 2 | 1 |
+----+---------------------+----------+-------------+
NOTE: The ID fields in my DB are actually using GUIDs, not ints as in this simple example.
Now, if I want to see who read article 1 as their first hit, I want my query to return users 1 and 2, but not 0, as user 0 saw article 0 as their first hit on the site. Conversely, if I want to see who read article 0 first, the query would only return user 0.
Here is my query thus far:
SELECT
*
FROM
pageviews
WHERE
articles_id = 1
GROUP BY
users_id
ORDER BY
time_in
But this returns distinct user IDs for all users who've read article 1, not filtering out the users who did not see it as their first result. I feel like I'm going the wrong direction with my query, so I'm turning towards you guys.
Thanks in advance.
One way to do it
SELECT v.users_id
FROM pageviews v JOIN
(
SELECT users_id, MIN(time_in) time_in
FROM pageviews
GROUP BY users_id
) q ON v.users_id = q.users_id AND v.time_in = q.time_in
WHERE v.articles_id = 1
Output:
| USERS_ID |
------------
| 1 |
| 2 |
Here is SQLFiddle demo
Another way:
SELECT users_id
FROM pageviews p
WHERE articles_id = 1
AND time_in = (SELECT MIN(time_in) from pageviews p2 WHERE p2.users_id = p.users_id)
SQLFiddle here