is it possible to get the average value for a column, as well as the average value for the same column with a conditional? or simply to combine these two queries into one.
SELECT AVG( field ) from table
SELECT AVG ( field ) from table where col = some_val
If there isn't a simple way to combine them using native mysql functions, would a stored function be able to handle it, or a user defined function?
Taking advantage of the fact that null values are not included in aggregate functions, we can use a CASE statement to control the average, as in the following:
select avg(amt) as average,
avg(case when col=some_val then amt else null end) as conditionalAverage
from myTable;
Sample Demo: http://sqlize.com/2IXwbWD2Eb
There is another way, not using case when
select
avg(amt) as average,
avg(if(col=some_val,amt,null)) as conditionalAverage
from myTable
Related
How to select COALESCE result to format( , 0)
my query is
SELECT (COALESCE((SELECT SUM(`invoices`.`paid_amount`) FROM `invoices`
WHERE DATE(`invoices`.`date`)=CURDATE()),0) +
COALESCE((SELECT SUM(`other_incomes`.`other_income_amount`) FROM `other_incomes`
WHERE DATE(`other_incomes`.`date`)=CURDATE()),0))
AS total
FROM
....
Primarily, COALESCE doesn't change the formatting. It only returns the first non-null value passed to it.
Also, instead of trying to join or do two different queries and adding, and handling all the sums and coalesces separately (not to mention the rounding), I would probably UNION all the relevant results together, then handle the coalesce/sum/round all at the end.
Try this:
SELECT round(sum(coalesce(amt, 0)), 0) as total
FROM (
SELECT paid_amount as amt
FROM invoices i
WHERE date(i.date) = CURDATE()
union all
SELECT other_income_amount
FROM other_incomes o
WHERE date(o.date) = CURDATE()
) z
Here I COALESCE first, to make nulls be 0 instead. I wrap that in a SUM to add up the values, and finally a ROUND to get the format. It was unclear from the question is you wanted to ROUND or FLOOR. If you are looking to get it with that comma, use FORMAT. Here's the mySQL documentation for that. You didn't specify your SQL flavor.
https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_format
Additionally, you should include your sql platform and version, the create statements for your tables, along with some insert statements that will provide sample data, along with the results you are looking for. It will help people answer your question. If you can include a fiddle, like https://dbfiddle.uk/, that would be nice.
I have a table as follows:
log (log_id, log_success (bool), log_created)
I would like to SELECT and return 3 columns date success and no_success, where the former does not exist in table and finally aggregate them by day.
I have created this query:
SELECT
log_created as 'date'
COUNT(*) AS 'count',
SUM(log_success) AS 'success'
SUM('count' - 'success') AS 'no_success'
FROM send_log
GROUP BY DATE_FORMAT(log_created, '%Y-%m-%d');
Would I be able to achieve it with this query? Is my syntax correct?
Thanks.
You can't reuse an alias defined in the select within the same select clause. The reason for this is that it might not even have been defined when you go to access it. But, you easily enough can repeat the logic:
SELECT
log_created AS date,
SUM(log_success) AS success,
COUNT(*) - SUM(log_success) AS no_success,
FROM send_log
GROUP BY
log_created;
I don't know why you are calling DATE_FORMAT in the group by clause of your query. DATE_FORMAT is usually a presentation layer function, which you call because you want to view a date formatted a certain way. Since it appears that log_created is already a date, there is no need to call DATE_FORMAT on it when aggregating. You also should not even need in the select clause, because the default format for a MySQL date is already Y-m-d.
You must select DATE_FORMAT(log_created, '%Y-%m-%d') if you want to group by this.
Also you can get the no_success counter with SUM(abs(log_success - 1))
SELECT
DATE_FORMAT(log_created, '%Y-%m-%d') date,
SUM(log_success) log_success,
SUM(abs(log_success - 1)) no_success
FROM send_log
GROUP BY date;
See the demo
I currently am using this query to select some data:
SELECT DISTINCT a.code AS code, name, max(scen.Is3D) AS Is3D FROM locations LEFT JOIN .... The scen table has columns Is3D and Date. I only want to select the max of items where the date IS NOT NULL. I tried max(scen.Is3D WHERE scen.Date IS NOT NULL), but that didn't work. I cannot change anything after the FROM in my query, so I need that filtering to be done in the MAX, if possible. I am using MySQL 5.7.
You can use:
MAX(CASE WHEN scen.date IS NOT NULL THEN scen.Is3D END) AS Is3D
The CASE expression returns NULL when none of the WHEN conditions is met, but MAX() ignores null values, so this will just return the max of the Is3D columns in the selected rows.
So if we can't change anything after the FROM, then we cannot get a perfect solution here. Since you are SELECTing out the NULL values. One thing that we can try if we can only modify the final output is this.
SELECT MAX(ISNULL(scen.Date,0))...
This will replace all the NULLs with 0, but it would help to know exactly what you are trying to do. Why are you so convinced that the query itself cannot be modified in any way?
The other solution would be to put the whole query in another wrapper.
That would look like:
SELECT *
FROM (
[your whole query here]
) AS inner
WHERE inner.Date IS NOT NULL
I want to calculate percentage for test groups.
I have group A,B and C. And I want to know how much success percentage each group have.
My first query is counting total test ran in each group by doing the following:
SELECT type, count(type) as total_runs
From mytable
Where ran_at > '2015-09-11'
Group by type
Second query is counting success for each group:
SELECT type, count(type) as success
FROM mytable
where run_status like '%success%' and ran_at> '2015-09-11'
Group by type
Now I need to divide one in the other and multiply in 100.
how do I do this in one query in an efficient way, I guess nested query is not so efficient- but anyway I can't see how I can uses nested query to solve it.
I would appreciate answer which include simple way, maybe not so efficient, and an efficient way with explanations
You can just use conditional aggregation:
SELECT type, sum(run_status like '%success%') as success,
100 * avg(run_status like '%success%') as p_success
FROM mytable
where ran_at> '2015-09-11'
Group by type;
In a numeric context, MySQL treats boolean expressions as integers with 1 for true and 0 for false. The above works assuming that run_status is not NULL. If it can be NULL, then you need an explicit case statement for the avg().
I had this one, but Gordon have a better solution if run_status is not NULL.
Select type, sum(if(run_status like '%success%',1,0)) / count(1) * 100) as p_success
From mytable
Where ran_at > '2015-09-11'
Group by type
Is it possible to "merge" 2 groups obtained after a SQL statement that use group by. For example if I have a field size ENUM('extra-small, 'small', 'medium', 'large', extra-large') and then I run this query SELECT * from clothes GROUP BY size;, but for in one case I would like to get in result "extra-small" and "small" in the same group. Is this possible with SQL?
yes, you can:
select count(*)
, case size
when 'extra-large'
then 'large'
else size end as grouped_size
from sizes
group by grouped_size
demo: http://sqlfiddle.com/#!2/ae3fa/2
How about using MySQL GROUP_CONCAT(expr)
This function returns a string result with the concatenated non-NULL
values from a group. It returns NULL if there are no non-NULL values.
Also have a look at MySQL – The GROUP_CONCAT() function