MySQL query group by with multiple sum values - mysql

If you review this SQL Fiddle, you will see that the resulting data is grouped by Year and Type which means that there are 2 rows for each year. I would like to only group on the year, and display the Sum of the A-type and the B-type on the same row.
Can someone please tell me how I would modify the sum statements in this query so that the first sum is only for the A-type, and the second sum is for the B-type? Thanks.

If you just want the two columns, it's fairly easy to do;
SELECT Year,
SUM(CASE WHEN Type='A' THEN Amt ELSE 0 END) TypeA,
SUM(CASE WHEN Type='B' THEN Amt ELSE 0 END) TypeB
FROM YourTable
GROUP BY Year
An SQLfiddle to test with.
...or a bit more verbose standard SQL;

How about this: http://sqlfiddle.com/#!2/85415/11
SELECT
SUM(IF(TYPE = 'A', Amt, 0)) AS A_amt,
SUM(IF(TYPE = 'B', Amt, 0)) AS B_amt,
YEAR,
TYPE
FROM YourTable
GROUP BY YEAR
Alternatively you could use a CASE statement which is standard SQL, but slightly longer so I opted for this version.

Related

Mysql 'greater than(>)' query always returns 0

I am working with a query where I want to display number of upcoming dates. The following query returns 0 even though there are dates greater than current date. Please help me to solve this problem.
SELECT (case when b.booked_date > cast(now() as date) then sum(1) else sum(0) end) as upcoming_booked_facilities
from svk_apt_book_facilities b
where b.customer_id = 1
and b.association_id = 1
and b.is_active = 1
group by b.facility_id
You need to sum a CASE expression to do conditional aggregation:
SELECT
facility_id,
SUM(CASE WHEN booked_date > CURDATE() THEN 1 ELSE 0 END) AS upcoming_booked_facilities
FROM svk_apt_book_facilities
WHERE
customer_id = 1 AND
association_id = 1 AND
is_active = 1
GROUP BY
facility_id;
You were trying to use the sum as the predicate of the CASE expression, which is probably not what you want. Note that I am also selecting the facility_id, since you are grouping by that column. If you instead want a conditional sum over the entire table, then don't select or group by facility.

How to query rows by month and group by column using mysql?

I have a database that has two columns - result and time
I'm trying to get a count of how many rows exist of each result in a particular month. There are only two options for result success and failure
I've managed to get a count of how many rows there are in each month, but I can't get the individual count of how many success and how many failure there were in each month.
Here is what I have:
SELECT result, MONTH(time) MONTH, COUNT(*) COUNT
FROM mytable
WHERE YEAR(time)=2017
GROUP BY MONTH(time);
I'm looking for a result that provides me with something like there were 12 successes and 8 failures in a particular month.
Any help would be appreciated.
Use conditional aggregation
SELECT result, MONTH(time) MONTH,
sum(result = 'success') as success_count,
sum(result = 'failure') as failure_count
FROM mytable
WHERE YEAR(time) = 2017
GROUP BY result, MONTH(time);
I would use the following query:
SELECT,
DATE_FORMAT(time, '%m %Y') AS month_year,
SUM(CASE WHEN result = 'success' THEN 1 ELSE 0 END) AS success_count,
SUM(CASE WHEN result = 'failure' THEN 1 ELSE 0 END) AS failure_count
FROM mytable
WHERE YEAR(time) = 2017
GROUP BY
DATE_FORMAT(time, '%m %Y')
Note that you should be aggregating by time period alone, and not by the result, which instead is part of the sum in the CASE expression.

Getting total using Union All

So here is my situation. I have 1 query that gets results grouped by date then I union all a second query that gets the totals (no grouping by date). My issue is I am calculating the average of fields and when I want to total up the average my numbers don't add up.
Here is my SQLFiddle
Here is my query:
SELECT
t.end,
SUM(CASE WHEN (t.start != t.end) THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1 END) / COUNT(t.id) as averageTime
FROM store t
GROUP BY t.end
UNION ALL
SELECT
'Total',
SUM(CASE WHEN (t.start != t.end) THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1 END) as averageTime
FROM store t
Right now the second query just gives the total not the total of the average. Any help is appreciated, thank you.
To clarify since there is some confusion...
I need to get the average per grouped date by how many items were in that group
timeDiff / count(t.id)
Since I am not grouping in the union all query it is doing it as a whole then dividing. I hope that makes more sense.
The first query is correct the data output is as follows:
1, 1.6667, 3 (Those are the averageTime values from the first query)
5.6667 (Should be the total row) Right now I have it out putting 10 that is the total before the first rows were averaged out.
THe first part of the query can probably be written as:
SELECT t.end,
AVG(CASE WHEN t.start != t.end THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1
END) as averageTime
FROM store t
GROUP BY t.end;
Presumably, you want the averages of the averages -- rather than the overall average. I assume this because your query is calculating the overall average.
One way is the brute force way:
SELECT t.end,
AVG(CASE WHEN t.start != t.end THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1
END) as averageTime
FROM store t
GROUP BY t.end
UNION ALL
SELECT 'Total', avg(AverageTime)
FROM (SELECT t.end,
SUM(CASE WHEN t.start != t.end THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1
END) as averageTime
FROM store t
GROUP BY t.end
) t;
Your question is not clear. But, I suppose you need Average. As #samD mentioned,
the second part of you query can be written as
SELECT
'Total',
AVG(CASE WHEN (t.start != t.end) THEN TIMESTAMPDIFF(DAY, t.start, t.end) ELSE 1 END) as averageTime
FROM store t
You're mistakenly assuming that the COUNT(t.id) in the first query represents the total number of rows, whilst it is actually also affected by the GROUP BY clause. If you multiply the separate rows by their number of days the totals also add up. Remove the division by COUNT(t.id) and the totals will add up, and you will correctly have the grouped SUMs as expected.
I'm just not sure how that solves your problem since you're not really clear on that: you simply cannot add all averages together and expect them to add up to a global average, that's not how math works: the sum of averages of arbitrary sized subgroups is rarely equal to the straight unweighted average of all groups together.

mysql how to combine two select statement

I have a database with records of date-time and a measurement value.
I've been writing two separate queries, one to return the total count of all daily records between certain times of day for the previous month, and the same query but a count of only when the measurement value is below threshold. I then manually divide the theshold count by total count for each day, and I am able to get a % uptime or SLA.
So I have two questions:
1) Can I combine these two queries into one query. I found the Answer to #1, see below
2) Can I go ahead and do the math in the queries, so what I get returned is just a listing of each day, the count above, the count below, and the % above or below threshold...
Sample data and query are listed below.
TableA
hostname, date_time, value
Sample Query to return days from previous month, excluding weekend days.
SELECT
count(*),
DATE(date_time),
SUM(
CASE WHEN rssi_val < 100
THEN 1
ELSE 0
END
)
FROM TableA
WHERE hostname = 'hostA'
AND DATE(date_time) BETWEEN '2013-07-01' AND '2013-07-31'
AND TIME(date_time) BETWEEN '06:00:00' AND '18:00:00'
AND DAYOFWEEK(date_time) NOT IN (1, 7)
GROUP BY DATE(date_time);
So now I just want to know how to add a 4th column that gives the percent uptime/downtime.
Have you tried this ?
select count(*),
DATE(date_time),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END),
SUM(CASE WHEN rssi_val<100 THEN 1 ELSE 0 END)/count(*) as percentage
from TableA
where hostname='hostA'
and DATE(date_time) between '2013-07-01' and '2013-07-31'
and TIME(date_time) between '06:00:00' and '18:00:00'
and DAYOFWEEK(date_time) NOT IN (1,7)
group by DATE(date_time);

MySQL SUM IF field b = field a

SELECT
incMonth as Month,
SUM( IF(item_type IN('typ1', 'typ2') AND incMonth = Month, 1, 0 ) )AS 'Total Sales'
FROM tester
I just need the sum for the current month its looping through.
If I'm reading that right, you'd need to use a group-by or at least a where clause to restrict things to just the time range you're wanting:
SELECT incMonth AS Month, SUM(IF(item_type IN('typ1', 'typ2'), 1, 0)) AS 'Total Sales'
FROM tester
GROUP BY incMonth