Dividing two COUNTS from mysql - mysql

Friends, I am trying to divide two COUNT(*) from MySQL:
I have this query:
SELECT 'Total ', COUNT(*)
FROM root4
WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE()
UNION
SELECT 'Good', COUNT(*)
FROM root4
WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE()
AND testresult ='OK'
The output of this query is looking like this:
________________________
|Total | COUNT(*) |
________________________
|Total| 42 |
|Good | 34 |
_______________________
What I want to achieve is to make another row under "Good" called "FPY" but the value to the dividing of "Good" to "Total" in percentage.
Something like this:
________________________
|Total | COUNT(*) |
________________________
|Total| 42 |
|Good | 34 |
|FPY | 80.95 |
_______________________
I tried to divide them like noob:
SELECT 'Total ', COUNT(*)
FROM root4
WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE()
UNION
SELECT 'Good', COUNT(*)
FROM root4 WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE()
AND testresult ='OK'
UNION
SELECT 'FPY', (COUNT(*)
FROM root4
WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE() /
UNION
SELECT 'Good', COUNT(*)
FROM root4
WHERE str_to_date(DATE, '%d.%m.%Y') = CURDATE()
AND testresult ='OK')
Of course, this is not working...
Note: Colum DATE is varchar that`s why I am using str_to_date.

Look for this:
SELECT COUNT(*) AS Total,
SUM(testresult ='OK') AS Good,
100 * COUNT(*) / SUM(testresult ='OK') AS FPY
FROM root4
WHERE `date` = DATE_FORMAT(CURRENT_DATE, '%d.%m.%Y')
is there any way to print it in two columns as I post in the question? – Azim Feta
WITH cte AS (
SELECT COUNT(*) AS Total,
SUM(testresult ='OK') AS Good
FROM root4
WHERE `date` = DATE_FORMAT(CURRENT_DATE, '%d.%m.%Y')
)
SELECT 'Total' AS indicator, Total AS value FROM cte
UNION ALL
SELECT 'Good', Good FROM cte
UNION ALL
SELECT 'FPY', 100 * Good / Total FROM cte

I think you could be needing a "SubQuery" here.
Something like this:
SELECT
Count(root4.*) AS Total,
root4_1.Good AS Good,
COUNT(root4.*) / root4_1.Good AS FYP
FROM
root4,
(
SELECT
COUNT(*) AS Good
FROM
root4
WHERE
str_to_date(DATE, '%d.%m.%Y') = CURDATE()
AND
testresult ='OK'
)AS root4_1
WHERE
str_to_date(DATE, '%d.%m.%Y') = CURDATE()
Also, see this question, which is similar: How to SELECT based on value of another SELECT

Related

How do I create multiple views in the same query in SQL and then join them?

This is the query that I am using.
I need to join the three views to calculate the monthly total revenue.
How should I proceed?
With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month)
With Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month)
With Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month
With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month),
Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month),
Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month
You need to "join" the subqueries
CREATE VIEw myview
AS (With Txn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE), '%y-%m') as Month, Sum(netPrice/100) as TransactionRevenue from transactions
group by Month)
, Leaves as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval -1 MONTH), '%y-%m') as Month, sum(amount/100) as LeaveRevenue from driverPaymentTransactions
group by Month)
, Sxn as(
Select DATE_FORMAT(DATE_ADD(createdAt, interval 330 MINUTE ), '%y-%m') as Month, sum(amount/100) as SubscribedRevenue from subscribedDriversDailyRevenues
group by MONTH)
Select * from Txn t
join Leaves l on t.Month = l.month
join Sxn s on t.month = s.month)
Do not join when you need to "pull" some different measures to the common attribute. Use union all, where you do not need to care about the most complete source of group values:
create table t1 as
select 1 as id, 10 as val union all
select 1, 20 union all
select 2, 30 union all
select 3, 49
create table t2 as
select 1 as id, 10 as val union all
select 3, 20 union all
select 3, 30 union all
select 5, 49
create table t3 as
select 4 as id, 10 as val union all
select 6, 20 union all
select 2, 30 union all
select 3, 49
with u as (
select
id
, val as t1_val
, cast(null as decimal) as t2_val
, cast(null as decimal) as t3_val
from t1
union all
select
id
, null as t1_val
, val as t2_val
, null as t3_val
from t2
union all
select
id
, null as t1_val
, null as t2_val
, val as t3_val
from t3
)
select
id
, sum(t1_val) as t1_val
, sum(t2_val) as t2_val
, sum(t3_val) as t3_val
from u
group by id
id | t1_val | t2_val | t3_val
-: | -----: | -----: | -----:
1 | 30 | 10 | null
2 | 30 | null | 30
3 | 49 | 50 | 49
5 | null | 49 | null
4 | null | null | 10
6 | null | null | 20
db<>fiddle here

MySQL - Count and GroupBy

I have this structure:
id| date_1 | date_2
---------------------
01|2017-01-01|2017-02-22
02|2017-01-02|2017-03-25
03|2017-02-10|2017-03-20
04|2017-03-11|2017-04-10
05|2017-03-15|2017-05-01
06|2017-03-20|2017-05-20
I would need this kind of result:
Month |Count(date_1)|Count(date_2)
---------------------------------
2017-01| 2 | 0
2017-02| 1 | 1
2017-03| 3 | 2
2017-04| 0 | 1
2017-05| 0 | 2
Now, I use this query (it works with only one date):
SELECT CONCAT(YEAR(date_1), '-', DATE_FORMAT(date_1,'%m')) AS month,
COUNT(*) AS items
FROM table
GROUP BY YEAR(date_1), MONTH(date_1)
ORDER BY date_1 DESC
You could union all the date values and then group and count them:
SELECT DATE_FORMAT(d, '%y-%m'), COUNT(*)
FROM (SELECT date_1 AS d FROM mytable
UNION ALL
SELECT date_2 FROM mytable) t
GROUP BY DATE_FORMAT(d, '%y-%m')
ORDER BY d DESC
To get the count of date_1 and date_2 in two different fields, with sub query:
SELECT DATE_FORMAT(temp1.d, '%y-%m'), COALESCE(d1count,0) AS date_1_count, COALESCE(d2count,0)AS date_2_count
FROM (
select date_1 as d from dates group by date_1
union all
select date_2 as d from dates group by date_2
) as temp1
LEFT JOIN (
select date_1, count(*) as d1count
from dates
group by DATE_FORMAT(date_1, '%y-%m')) as temp2
on DATE_FORMAT(temp2.date_1, '%y-%m') = DATE_FORMAT(temp1.d, '%y-%m')
LEFT JOIN (
select date_2, count(*) as d2count
from dates
group by DATE_FORMAT(date_2, '%y-%m')) as temp3
on DATE_FORMAT(temp3.date_2, '%y-%m') = DATE_FORMAT(temp1.d, '%y-%m')
GROUP BY DATE_FORMAT(temp1.d, '%y-%m')
Consider using subqueries behind SELECT
SELECT distinct DATE_FORMAT(t.d, '%y-%m'),
(
SELECT count(*)
FROM your_table as dd
where DATE_FORMAT(dd.date_1, '%y-%m') = DATE_FORMAT(t.d, '%y-%m')
) as count_date_1,
(
SELECT count(*)
FROM your_table as dd
WHERE DATE_FORMAT(dd.date_2, '%y-%m') = DATE_FORMAT(t.d, '%y-%m')
) as count_date_2
FROM
(
SELECT date_1 AS d FROM your_table
UNION ALL
SELECT date_2 as d FROM your_table
) as t
dbfiddle demo

MYSQL get total sum and sum between 2 date in 1 query

I am trying to get the total sum of a column and the sum of the same column between 2 dates in one query. is this possible?
My table looks like this:
uid|amount|date
The two queries i am trying to make one of:
SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1
SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1 AND YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE)
You could use a UNION query:
SELECT 'All' AS cnt, sum(amount) as `keys` FROM tbl_keys WHERE uid = 1
UNION ALL
SELECT 'Current_month' AS cnt, sum(amount) as `keys`
FROM tbl_keys
WHERE
uid = 1
AND `date`<= last_day(current_date)
`date`>= current_date - interval (day(current_date)-1) day
(I prefer to use >= and <= on the date column, as it can make use of an index if present, while functions like MONTH() or YEAR() cannot, also I assume that date is a date columnd and that it doesn't contain time informations).
If you want the result in one row, you could use an inline query:
SELECT
(SELECT sum(amount) as `keys` FROM tbl_keys WHERE uid = 1) AS total,
(SELECT sum(amount) as `keys`
FROM tbl_keys
WHERE
uid = 1
AND `date`<= last_day(current_date)
`date`>= current_date - interval (day(current_date)-1) day
) AS current_month
Something like this:
SELECT sum(amount) as `keys`,
(
SELECT sum(t.amount)
FROM tbl_keys as t
WHERE t.uid = tbl_keys.uid AND YEAR(t.`date`) = YEAR(CURRENT_DATE)
AND MONTH(t.`date`) = MONTH(CURRENT_DATE)
) as `keys2`
FROM tbl_keys
WHERE uid = 1
SELECT sum(amount) AS `keys`
FROM (
SELECT amount FROM tbl_keys
UNION ALL
SELECT amount FROM tbl_keys
WHERE uid = 1
AND YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE)
) AS new_table;
Using a UNION clause, you will get the desired output you want.
Use CASE to count only the amount for the specified date:
SELECT SUM(amount) AS `keys`,
SUM(CASE WHEN YEAR(`date`) = YEAR(CURRENT_DATE)
AND MONTH(`date`) = MONTH(CURRENT_DATE) THEN amount ELSE 0 END) AS 'keys2'
FROM tbl_keys
WHERE uid = 1
;
My guess is that this will run more efficient than a solution using UNION SELECT.

Hour Wise data in mySql

I have the table with following fields
Createdon(datetime)
Amount(double)
I need to find the sum of amounts for next 24 hours of the given date. If there are no results then the sum should be zero.
e.g
duration sum
0000-0001 25.43
0001-0002 36.85
0002-0003 0
.
.
.
.
0022-0023 38.56
Can you please help me creating a query to find the required solution
The key to your query is the ability to take any datetime value and truncate it to the nearest preceding hour. You can do that with this expression:
DATE_FORMAT(Createdon, '%Y-%m-%d %H:00')
Given, for example, 2015-04-21 14:22:05, this gives back 2015-04-21 14:00:00.
Then you use that in GROUP BY
SELECT DATE_FORMAT(Createdon, '%Y-%m-%d %H:00') Createdhour,
SUM(Amount) sum
FROM theTable
GROUP BY DATE_FORMAT(Createdon, '%Y-%m-%d %H:00')
ORDER BY DATE_FORMAT(Createdon, '%Y-%m-%d %H:00')
Finally, I think you wanted one day's worth of results. You need to add a WHERE clause to get that. The one shown here will take yesterday's results -- that is, all results from [midnight yesterday -- midnight today).
SELECT DATE_FORMAT(Createdon, '%Y-%m-%d %H:00') Createdhour,
SUM(Amount) sum
FROM theTable
WHERE CreatedOn >= DATE(NOW()) - INTERVAL 1 DAY
AND CreatedOn < DATE(NOW())
GROUP BY DATE_FORMAT(Createdon, '%Y-%m-%d %H:00')
ORDER BY DATE_FORMAT(Createdon, '%Y-%m-%d %H:00')
This is explained in greater detail at http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
To include all hours of the day, you will need an independent source of distinct DATETIME items.
Here's a query that will do such a thing.
SELECT mintime + INTERVAL seq.seq HOUR AS CreatedHour
FROM (
SELECT DATE(NOW()) - INTERVAL 1 DAY AS mintime,
DATE(NOW()) AS maxtime
) AS minmax
JOIN seq_0_to_23 AS seq
ON seq.seq < TIMESTAMPDIFF(HOUR,mintime,maxtime)
You then need to use LEFT JOIN to pick up your data.
SELECT a.Createdhour,
SUM(Amount) sum
FROM (
SELECT mintime + INTERVAL seq.seq HOUR AS CreatedHour
FROM (
SELECT DATE(NOW()) - INTERVAL 1 DAY AS mintime,
DATE(NOW()) AS maxtime
) AS minmax
JOIN seq_0_to_23 AS seq
ON seq.seq < TIMESTAMPDIFF(HOUR,mintime,maxtime)
) a
LEFT JOIN theTable t
ON a.CreatedHour = DATE_FORMAT(t.Createdon, '%Y-%m-%d %H:00')
GROUP BY DATE_FORMAT(t.Createdon, '%Y-%m-%d %H:00')
ORDER BY DATE_FORMAT(t.Createdon, '%Y-%m-%d %H:00')
Finally, you need to somehow get that table seq_0_to_23. If you're running MariaDB, it's built in. If not...
CREATE TABLE seq_0_to_23 AS
SELECT 0 AS seq
UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18
UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21
UNION ALL SELECT 22 UNION ALL SELECT 23
This is written up in more general form at http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/

MySQL Count IF and JOIN

I have two tables:
deskcases: | CaseID | Resolved At(Date) | Labels |
ringcentral: | Date | Type | Action Result |
My goal is to have the following output for the previous 7 days :
| Date | Count of TotalResolvedCases | Count of Total Calls |
I need to count the cases and calls in two separate tables then join and group the counts by the date. I'm also dealing with differing date formatting in the two tables, hence the wacky group by and join functions.
I also need to to have the join include all dates in the previous 7 days (deskcases has all dates so an INNER JOIN should work here I thought?)
To close, I've tried to run the following query below and it just churns with no result after a minute or two. Any idea on how to get this working? Thank you in advance for your help! :-)
(Running MySQL 5.0.96)
SELECT
DATE_FORMAT(
deskcases.`Resolved At`,
'%Y-%m-%d'
)AS Date1,
(
SELECT
COUNT(deskcases.`Case #`)
FROM
deskcases
WHERE
deskcases.Labels NOT LIKE '%SPAM%'
AND deskcases.Labels NOT LIKE '%Online Orders%'
AND deskcases.Labels NOT LIKE '%Internal SPAM%'
AND deskcases.`Resolved At` > NOW()- INTERVAL 8 DAY
)AS TotalResolvedCases,
(
SELECT
COUNT(ringcentral.Counter)
FROM
ringcentral
WHERE
`ringcentral`.`Type` = 'Voice'
AND `Action Result` = 'Accepted'
AND ringcentral.`Date` > NOW()- INTERVAL 8 DAY
)AS TotalCalls
FROM
deskcases
INNER JOIN ringcentral ON DATE_FORMAT(
deskcases.`Resolved At`,
'%Y-%m-%d'
)= ringcentral.Date
GROUP BY
Date1
ORDER BY
Date1 ASC
EDIT
I was able to edit this slightly to give me some result but it seems like I am counting ALL cases and calls with my sub-select queries and the totals are not being grouped by date. Here is the code:
SELECT
DATE_FORMAT(
deskcases.`Resolved At`,
'%Y-%m-%d'
)AS Date1,
(
SELECT
COUNT(deskcases.`Case #`)
FROM
deskcases
WHERE
deskcases.Labels NOT LIKE '%SPAM%'
AND deskcases.Labels NOT LIKE '%Online Orders%'
AND deskcases.`Case Status` LIKE '%Resolved%'
)AS TotalResolvedCases,
(
SELECT
COUNT(ringcentral.Counter)
FROM
ringcentral
WHERE
`ringcentral`.`Type` = 'Voice'
AND `Action Result` = 'Accepted'
)AS TotalCalls
FROM
deskcases
LEFT OUTER JOIN ringcentral ON DATE_FORMAT(
deskcases.`Resolved At`,
'%Y-%m-%d'
)= ringcentral.Date
WHERE deskcases.`Resolved At` > NOW()- INTERVAL 8 DAY
GROUP BY
Date1
ORDER BY
Date1 ASC
In this case you should definitely not join on date.
For example you may have this data:
deskcases ringcentral
--------- -----------
date | whatever_d date | whatever_r
---------------------- ----------------------
today x yesterday u
yesterday y
yesterday z
Now, when you join them you'll get this:
joinedTable
-----------
date | whatever_d | whatever_r
-------------------------------------
today x
yesterday y u
yesterday z u
Oops, you got 2 times an entry from ringtones table, but you wanted just 1.
So, how do you get your data? Either write 2 statements or combine them with UNION:
SELECT
DATE(`Resolved At`) AS Date1,
"Deskcases" AS fromTable,
COUNT(*) AS TotalNumber
FROM
deskcases
WHERE
deskcases.Labels NOT LIKE '%SPAM%'
AND deskcases.Labels NOT LIKE '%Online Orders%'
AND deskcases.Labels NOT LIKE '%Internal SPAM%'
AND deskcases.`Resolved At` > CURDATE()- INTERVAL 8 DAY
GROUP BY 1, 2
UNION ALL
SELECT
`Date` AS Date1,
"ringcentral" AS fromTable,
COUNT(*) AS TotalNumber
FROM
ringcentral
WHERE
`ringcentral`.`Type` = 'Voice'
AND `Action Result` = 'Accepted'
AND ringcentral.`Date` > CURDATE()- INTERVAL 8 DAY
GROUP BY 1, 2
Also note, that I changed NOW() to CURDATE(). In deskcases table your date column seems to be a timestamp. When you subtract 8 days from '2013-03-20 10:06:00' you'll get '2013-03-12 10:06:00' and therefore you'll be missing all rows between '2013-03-12 00:00:00' and '2013-03-12 10:05:59'. Also I just used the DATE() function instead of DATE_FORMAT(). DATE_FORMAT() is a really nice and useful function in many ways, but in this case you have to type less characters when using DATE() :)
UPDATE:
SELECT
Date1,
SUM(CASE WHEN fromTable = 'Deskcases' THEN TotalNumber ELSE 0 END) AS TotalDeskcases,
SUM(CASE WHEN fromTable = 'ringcentral' THEN TotalNumber ELSE 0 END) AS TotalRingcentral
FROM (
SELECT
DATE(`Resolved At`) AS Date1,
'Deskcases' AS fromTable,
COUNT(*) AS TotalNumber
FROM
deskcases
WHERE
deskcases.Labels NOT LIKE '%SPAM%'
AND deskcases.Labels NOT LIKE '%Online Orders%'
AND deskcases.Labels NOT LIKE '%Internal SPAM%'
AND deskcases.`Resolved At` > CURDATE()- INTERVAL 8 DAY
GROUP BY 1, 2
UNION ALL
SELECT
`Date` AS Date1,
'ringcentral' AS fromTable,
COUNT(*) AS TotalNumber
FROM
ringcentral
WHERE
`ringcentral`.`Type` = 'Voice'
AND `Action Result` = 'Accepted'
AND ringcentral.`Date` > CURDATE()- INTERVAL 8 DAY
GROUP BY 1, 2
) sq
GROUP BY Date1