I have written this query to get my data, and all the data is fine.
I have one column which has either Pass Or Fail. I want to calculate the % of number of bookings that failed, and output it in a single value.
I will have to write another query to show that one number.
For example : The below data, I have 4 bookings , out which 2 failed. So 50% is the failure rate. I am omitting some columns , in the display, but can be seen in the query.
That's an aggregation over all records and simple math:
select count(case when decision = 'Fail' then 1 end) / count(*) * 100
from (<your query here>) results;
Explanation: COUNT(something) counts non null values. case when decision = 'Fail' then 1 end is 1 (i.e. not null) for failures and null otherwise (as null is the default for no match in CASE/WHEN ‐ you could as well write else null end explicitly).
Modify your original condition to the following. Notice that there is no need to wrap your query in a subquery.
CONCAT(FORMAT((100 * SUM(CASE WHEN trip_rating.rating <= 3 AND
(TIMESTAMPDIFF(MINUTE,booking.pick_up_time,booking_activity.activity_time) -
ROUND(booking_tracking_detail.google_adjusted_duration_driver_coming/60)) /
TIMESTAMPDIFF(MINUTE,booking.pick_up_time,booking_activity.activity_time)*100 >= 15
THEN 1
ELSE 0
END) / COUNT(*)), 2), '%') AS failureRate
This will also format your failure rate in the format 50.0%, with a percentage sign.
Related
I try to collect general statistics on the depth of correspondence: average, maximum and minimum number of messages of each type per one request. Have 2 tables:
First:
ticketId,ticketQueueId,ticketCreatedDate
Second:
articleId,articleCreatedDt,articleType (can be IN or OUT - support responses), ticketId
I reasoned like this:
SELECT AVG(COUNT(articleType='IN')) AS AT_IN, AVG(COUNT(articleType='OUT')) AS AT_OUT
FROM tickets.tickets JOIN tickets.articles
ON tickets.ticketId=articles.ticketId;
GROUP BY tickets.ticketId
but it doesn't work.
Error Code: 1111. Invalid use of group function
you can't use nested aggregation function (AVG(COUNT())) but use proper subquery and apply the aggregation function the the subquery gradually
also your use of of count in improper
the count function count each row where the related column is not null so in your case the evaluation articleType='IN' (or articleType='OUT') returning 0 or 1 is never null
select AVG(T_IN), AVG(T_OUT)
from (
SELECT sum(case when articleType='IN' then 1 else 0 END AS T_IN, sum(case when articleType='OUT' then 1 else 0 END AS T_OUT
FROM tickets.tickets
JOIN tickets.articles ON tickets.ticketId=articles.ticketId
GROUP BY tickets.ticketId
) t
(and You have also a wrong semicolon )
What is the difference below if I use case instead of sum? I believe I would get the same output?
SELECT SUM(CASE WHEN salary > 100000 THEN 1 ELSE 0 END) AS Total
SELECT COUNT(CASE WHEN salary > 100000 THEN 1 END) AS Total
SELECT COUNT(CASE WHEN salary > 100000 THEN 1 ELSE NULL END) AS Total
Thanks!
Per the other answer, all forms are equivalent. There also a couple of other form that are more compact and achieve the same result:
count_if(salary > 100000)
count(if(salary > 100000, 1))
However, the idiomatic and more general way to do this in Trino (formerly known as Presto SQL) is:
SELECT count(*) FILTER (WHERE salary > 100000) AS Total
FROM ...
See the documentation for more details about filtered aggregations.
All other forms except for the one based on SUM should, per the SQL specification, raise a warning to indicate that null values have been eliminated. This behavior is not yet implemented in Trino, but will be added at some point in the future.
The three are equivalent. All of them count the number of rows that meet the particular condition (salary > 100000). All return 0/1 and would not return NULL values for the column.
From a performance perspective, all should be equivalent as well. I have a personal preference for the first version. I consider the third to be unnecessarily verbose because else NULL is the default for a case expression.
Hi I was looking for a mysql query result like
As you can see there are some values have the kind of values (Ex: BV and BR or C5 and C7) how can I combine then together into one common value lets say B or C and group by that in sql?
I have the following query:
SELECT
type,
sum(case when status ='valid' then 1 else 0 end) valid_jobs,
sum(case when status ='non-valid' then 1 else 0 end) non_valid_jobs,
sum(case when status IS NULL then 1 else 0 end) null_jobs
from
main_table
where
SUBSTRING_INDEX(CAST(CAST(from_unixtime(date_generated) AS DATE) AS CHAR), '-',2) REGEXP '^2016'
group by type
Thanks in advance guys.
Otcome will look like:
Just use an expression that evaluates the value of the type column, and returns the desired result.
What's not clear from the question is the "mapping" from type to the value you want returned in the first column. It looks like we might be looking at just the first character of value in the type column.
SUBSTR(type,1,1)
If the "mapping" is more involved, then we could use a CASE expression. For example:
CASE
WHEN type IN ('BV','BR','BT','ZB') THEN 'B'
WHEN type IN ('C5','C7') THEN 'C'
WHEN ... THEN ...
ELSE type
END
We'd use that as the first expression in the SELECT list (replacing the reference to the type column in the original query), and in the GROUP BY clause.
On an (unrelated) performance note, we'd prefer conditions in the WHERE clause to be on bare columns. That allows MySQL to make use of an (efficient) range scan operation on an appropriate index.
With this condition:
WHERE SUBSTRING_INDEX(CAST(CAST(FROM_UNIXTIME( t.date_generated ) AS DATE) AS CHAR), '-',2)
REGEXP '^2016'
We're forcing MySQL to evaluate the expression on the left side for every row in the table. And the value returned by the expression is compared.
If what we're really trying to do is get date_generated values in 2016, assuming that date_generated is INTEGER type, storing 32-bit unix-style number of seconds since beginning of the era 1970-01-01...
We can do something like this:
WHERE t.date_generated >= UNIX_TIMESTAMP('2016-01-01')
AND t.date_generated < UNIX_TIMESTAMP('2017-01-01')
MySQL will see that as a range operation on the values in te date_generated column. And with that, MySQL can make effective use of an index that has date_generated as a leading column.
Just replace expr with the expression that returns the values you want in the first column:
SELECT expr
, SUM(IF( t.status = 'valid' ,1,0)) AS valid_jobs
, SUM(IF( t.status = 'non-valid' ,1,0)) AS non_valid_jobs
, SUM(IF( t.status IS NULL ,1,0)) AS null_jobs
FROM main_table t
WHERE t.date_generated >= UNIX_TIMESTAMP('2016-01-01')
AND t.date_generated < UNIX_TIMESTAMP('2017-01-01')
GROUP BY expr
EDIT
To guarantee that rows are returned in a particular sequence, add an ORDER BY clause, e.g.
ORDER BY 1
try this,
SELECT
LEFT(type,1) AS type,
sum(case when status ='valid' then 1 else 0 end) valid_jobs,
sum(case when status ='non-valid' then 1 else 0 end) non_valid_jobs,
sum(case when status IS NULL then 1 else 0 end) null_jobs
FROM
main_table
WHERE
SUBSTRING_INDEX(CAST(CAST(from_unixtime(date_generated) AS DATE) AS CHAR), '-',2) REGEXP '^2016'
GROUP BY
type
I have a MySQL table which records values in a database when a user has paid by voucher. It records the voucher value. I need to get a total sum of all voucher values broken down by the voucher amount. The query I currently have is below. However the butchery_class_voucher_155 and butchery_class_voucher_135 are always returned as 0.
Please help to solve this problem.
select
case
when voucher_value = '155.00'
then round(sum(voucher_value/1.2), 2)
else 0.00 end
as butchery_class_voucher_155,
case
when voucher_value = '10.00'
then round(sum(voucher_value/1.2), 2)
else 0.00 end
as shop_voucher,
case when voucher_value = '135.00'
then round(sum(voucher_value/1.2), 2)
else 0.00 end
as butchery_class_voucher_135,
ifnull(round(sum(final_price/1.2), 2),0.00) as paidbycard,
ifnull(round(sum(transfer_fee/1.2), 2),0.00) as transfer_fee
from `bookings`
where `location_id` = 6
The problem is that you have the sum() call within a case, even though the cases (or ifs) should be inside the sum(). With your current code, if the 1st record has a voucher_value of 10, then only the shop_voucher expression will give you any result other than zero.
select
round(sum(if(voucher_value=155,voucher_value/1.2,0)), 2) as butchery_class_voucher_155,
...
from `bookings`
where `location_id` = 6
You need to consider one more thing: where exactly you put your rounding function. You can sum the results first and then round that (this is what is used in my code above), or you can apply the rounding at each and every division.
The reason this is failing is due to the way you have set up your case statement. You've written a query to give you the sum if the voucher_value equals a certain value, or to give you zero. On the last row the query analyzes, it will only compare that voucher value, and the others will return as 0.
To fix this, you need to adjust your SUM() function to add the voucher value in the case that the value matches, otherwise to add 0:
SELECT ROUND(SUM(CASE WHEN voucher_value = 155 THEN (voucher_value / 1.2) ELSE 0 END), 2) AS butchery_class_voucher_155...
And so on.
I Need to retrieve values from database to plot them in graph. For that I need to get values on criteria basis. Data matching different criteria has to be returned as different rows/ column to my query
(i.e)
I have a table called TABLEA which has a column TIME. I need to get the value based on time critreia as a result, count of rows which are matching TIME>1 and TIME<10 as a result, TIME>11 and TIME <20 as a result and so on. Is it possible to get the values in a single query. I use Mysql with JDBC.
I should plot all the counts in a graph
Thanks in advance.
select sum(case when `time` between 2 and 9 then 1 else 0 end) as count_1,
sum(case when `time` between 12 and 19 then 1 else 0 end) as count_2
from your_table
This can be done with CASE statements, but they can get kind of verbose. You may just want to rely on Boolean (true/false) logic:
SELECT
SUM(TIME BETWEEN 1 AND 10) as `1 to 10`,
SUM(TIME BETWEEN 11 and 20) as `11 to 20`,
SUM(TIME BETWEEN 21 and 30) as `21 to 30`
FROM
TABLEA
The phrase TIME BETWEEN 1 AND 10) will either returnTRUEorFALSEfor each record.TRUEbeing equivalent to1andFALSEbeing equivalent to0`, we then only need sum the results and give our new field a name.
I also made the assumption that you wanted records where 1 <= TIME <= 10 instead of 1 < TIME < 10 which you stated since, as stated, it would drop values where the TIME was 1,10,20, etc. If that was your intended result, then you can just adjust the TIME BETWEEN 1 AND 10 to be TIME BETWEEN 2 AND 9 instead.