Percentage above a number in Mysql - mysql

I have a column in my table that shows how many seconds the customer was in line to be served, in seconds.
I need to put together a query that shows how many percent of chats were served within 30 seconds.
I was only able to count the number of calls over the ideal period, but I couldn't get the percentage of chats that were within that ideal period.
SELECT
COUNT(c.id) AS 'Total'
FROM lh_chat as c
LEFT JOIN lh_departament as d ON c.dep_id = d.id
INNER JOIN lh_users u ON c.user_id = u.id
WHERE FROM_UNIXTIME(c.time-10800, '%Y-%m-%d') BETWEEN '2023-01-01' AND '2023-01-31'
AND u.id != 178
AND c.`status` <> 0
AND c.dep_id IN (7,19,23)
AND c.wait_time > 30
I was only able to add the number of chats above the ideal time, but not to make the percentage of chats that are within the expected range

Could you try this:
SELECT SUM(IF(c.wait_time > 30, 0, 1) * 1.0 / COUNT(c.id)
FROM lh_chat as c
LEFT JOIN lh_departament as d ON c.dep_id = d.id
INNER JOIN lh_users u ON c.user_id = u.id
WHERE FROM_UNIXTIME(c.time-10800, '%Y-%m-%d') BETWEEN '2023-01-01' AND '2023-01-31'
AND u.id != 178
AND c.`status` <> 0
The idea is to count only wait_times less then 30 seconds using SUM and then divide to the total count.
AND c.dep_id IN (7,19,23)

Related

Query! how can i get total meals and cost from three tables for each user! This is my first question so sorry for the inconvenience

enter image description herei have three tables users,meals,expense. I want to calculate users meal,expense between date display with a single query.
i have tried in many ways. Like
SELECT u.name as BorderName , SUM(e.expenseAmount) as expense
FROM users u
INNER JOIN expenses e on e.user_id=u.id
WHERE e.expenseDate BETWEEN '2019.04-01' AND '2019.04.30'
GROUP BY e.user_id
do the aggregation inline views, with the inline view returning a single row per user_id, to avoid semi-Cartesian product (partial cross product)
Something like this:
SELECT u.name
, IFNULL(t.tot_expenseamount,0) AS tot_expense_amount
, IFNULL(n.tot_noofmeal,0) AS tot_no_of_meal
FROM users u
LEFT
JOIN ( SELECT e.user_id
, SUM(e.expenseamount) AS tot_expenseamount
FROM expense e
WHERE e.expensedate >= '2019-04-01' + INTERVAL 0 MONTH
AND e.expensedate < '2019-04-01' + INTERVAL 1 MONTH
GROUP
BY e.user_id
) t
ON t.user_id = u.id
LEFT
JOIN ( SELECT m.user_id
, SUM(m.noofmeal) AS tot_noofmeal
FROM meal m
WHERE m.mealdate >= '2019-04-01' + INTERVAL 0 MONTH
AND m.mealdate < '2019-04-01' + INTERVAL 1 MONTH
GROUP
BY m.user_id
) n
ON n.user_id = u.id
ORDER
BY u.name
Note that the inline view queries n and t return single row per user_id, with total expense amount or total number of meals. For testing, each inline view query can be executed separately, to verify the results.

Restricting query data in mysql

I am getting back into mysql after a couple years and have run into a problem. I have a query that works, but I am lost on how to optimize it better.
Here is the query:
select
u.id as 'User',
count(distinct tr.id) as Trips,
count(distinct ti.id) as 'Trip Items'
from
users u
inner join
user_emails ue on u.id = ue.user_id
inner join
trips tr on tr.user_id = u.id
inner join
trip_items ti on ti.trip_id = tr.id
where
ue.verified = true and ue.is_primary = true
and
tr.created_at between '2017-02-01 00:00:00' and '2017-02-01 00:59:59'
group by 1
having Trips < 30
I essentially need to get a count of all trips and trip items.. but only for those users who have 30 or less trips in the given date range. Right now I am accomplishing that by grouping the results by User, and then performing a 'having'. I'm looking at millions of results on a non-indexed field (created_at). ideally i'd like to just get 1 row back that has total trips, and total trip items. But still applying the "users w/ less than 30 trips" during the query. Is this possible? :)
Just a quick edit, i've tried looking around at other solutions but I am a bit lost on what I should be looking for. I'm not looking for a solution, perhaps just a "go check this out and try that".
count(distinct) can be expensive. Try aggregating before doing the join. I think the follow works (this assumes that items are not shared among different trips):
select u.id as `User`, tr.Trips, tr.items
from users u inner join
user_emails ue
on u.id = ue.user_id inner join
(select tr.user_id, count(*) as Trips, sum(items) as items
from trips tr join
(select ti.trip_id, count(*) as items
from trip_items ti
group by ti.trip_id
) ti
on ti.trip_id = tr.id
where tr.created_at >= '2017-02-01' and tr.created_at < '2017-02-01 01:00:00'
group by tr.user_id
having trips < 30
) tr
on tr.user_id = u.id inner join
where ue.verified = true and ue.is_primary = true
group by 1

SQL- How to combine two tables with two table counts with different conditions

Query in text: "Display all active users and the completed orders entered by them + the completed orders they are assigned to for the specified date range".
Here is the query i managed to create with only one count
SELECT u.firstname, u.lastname, COUNT(l.id) AS totalCompleted
FROM users u
LEFT JOIN orders l
ON l.idDispatcher = u.id
WHERE u.disabled = '0'
AND l.smallStatus='1'
AND l.dateAdded >= :from
AND l.dateAdded <= :to
GROUP BY u.firstname;
This gives me all the orders where the user is assigned to an order:
LEFT JOIN orders l
ON l.idDispatcher = u.id
I need to combine this query with another one where the COUNT(l.id) is based on:
LEFT JOIN orders l
ON l.addedById= u.id
When I try this:
LEFT JOIN orders l
ON l.idDispatcher = u.id AND l.addedById= u.id
The COUNT(l.id) combines the result for assigned orders and orders added by the user, when i need it to be with two different numbers. I also tried putting a condition inside the COUNT, with no success
Not sure I understand exactly but if you said you got it working with two separate queries, and you need two counts, then just union the results together?
But if you need one count of ALL matches based on two separate conditions, use an "OR" in your join instead of "AND":
SELECT u.firstname, u.lastname, COUNT(l.id) AS totalCompleted
FROM users u
LEFT JOIN orders l
ON l.idDispatcher = u.id
or l.addedById= u.id
WHERE u.disabled = '0'
AND l.smallStatus='1'
AND l.dateAdded >= :from
AND l.dateAdded <= :to
GROUP BY u.firstname, u.lastname;

Sql count returns wrong numbers

i have an api which i make calls to and i need alot of data from different tables so i use joins on them, now the problem is that whilst i have 4 replies, and 5 interactions the data always returns 20 replies and 20 interactions this is the result:
screen_name screen_state replies interactions alerts
sjerd 0 20 20 0
i use this query to count the records and results:
SELECT u.screen_name,
u.screen_state,
count(r.id) AS replies,
count(i.id) AS interactions,
count(a.alerts) AS alerts
FROM users u
LEFT JOIN reply r ON u.id = r.user
LEFT JOIN interactions i ON u.id = i.user_id
LEFT JOIN alerts a ON u.id = a.user_id WHERE u.id ='2'
GROUP BY u.id, u.screen_state
can someone see why it's returning 20 while i only have 7 rows of replies in total in reply table,
and 5 rows of interactions in total in interaction table.
each row is 1 reaction or reply.
Your counts are always going to give the same result as all tables are joined at the same level.
You need to do your counts as inline sub-queries (or whatever - I can never remember the correct terminology):
SELECT u.screen_name,
u.screen_state,
(select count(*) from reply r where u.id = r.user) AS replies,
(select count(*) from interactions i where u.id = i.user_id) AS interactions,
(select count(*) from alerts a where u.id = a.user_id) AS alerts
FROM users u
WHERE u.id ='2'
SELECT u.screen_name, u.screen_state,
count(DISTINCT r.id) AS replies,
count(DISTINCT i.id) AS interactions,
count(DISTINCT a.alerts) AS alerts
FROM users u
LEFT JOIN reply r ON u.id = r.user
LEFT JOIN interactions i ON u.id = i.user_id
LEFT JOIN alerts a ON u.id = a.user_id WHERE u.id ='2'
GROUP BY u.id, u.screen_state

SELECT statement subquery

EDIT: I need the overall total in there subtracting both direct and indirect minutes.
I'm trying to SUM M. Minutes as an alias "dminutes". Then, take the SUM of M.minutes again and subtract M.minutes that have "indirect" column value (and give it "inminutes" alias). However, it's showing me null, so the syntax is wrong. Suggestions?
table = tasks
column = task_type
Example:
M.minutes total = 60 minutes
M. minutes (with "direct" task_type column value) = 50 minutes (AS dminutes)
M. minutes (with "indirect" task_type column value) = 10 minutes (AS inminutes)
SQL statement:
SELECT
U.user_name,
SUM(M.minutes) as dminutes,
ROUND(SUM(M.minutes))-(SELECT (SUM(M.minutes)) from summary s WHERE ta.task_type='indirect') as inminutes
FROM summary S
JOIN users U ON U.user_id = S.user_id
JOIN tasks TA ON TA.task_id = S.task_id
JOIN minutes M ON M.minutes_id = S.minutes_id
WHERE DATE(submit_date) = curdate()
AND TIME(submit_date) BETWEEN '00:00:01' and '23:59:59'
GROUP BY U.user_name
LIMIT 0 , 30
I think something like this should work.
You might have to tweak it a little.
SELECT direct.duser_id, indirect.iminutes, direct.dminutes,
direct.dminutes - indirect.iminutes FROM
(SELECT U.user_id AS iuser_id, SUM(M.minutes) AS iminutes
FROM summary S
JOIN users U
ON U.user_id = S.user_id
JOIN minutes M
ON M.minutes_id = S.minutes_id
JOIN tasks TA
ON TA.task_id = S.task_id
WHERE TA.task_type='indirect'
AND DATE(submit_date) = curdate()
AND TIME(submit_date) BETWEEN '00:00:01' and '23:59:59'
GROUP BY U.user_id) AS indirect
JOIN
(SELECT U.user_id AS duser_id, SUM(M.minutes) AS dminutes
FROM summary S
JOIN users U
ON U.user_id = S.user_id
JOIN minutes M
ON M.minutes_id = S.minutes_id
JOIN tasks TA
ON TA.task_id = S.task_id
WHERE TA.task_type='direct'
AND DATE(submit_date) = curdate()
AND TIME(submit_date) BETWEEN '00:00:01' and '23:59:59'
GROUP BY U.user_id) AS direct
WHERE indirect.iuser_id = direct.duser_id
SUM is a nasty little function:
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_sum
Returns the sum of expr. If the return set has no rows, SUM() returns
NULL. The DISTINCT keyword can be used to sum only the distinct values
of expr.
SUM() returns NULL if there were no matching rows.
Try wrapping SUM to a COALESCE or an IFNULL:
... COALESCE( SUM(whatever), 0) ...