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
Related
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
I currently have a query that provides the result set below, I now need to add to this query to provide a total at the bottom of all the sales. I am not sure how to do this.
Current query:
SELECT
product,
COUNT(OrderNumber) AS CountOf
FROM
orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
GROUP BY
product
ORDER BY CountOf DESC
Current Resultset:
product| count
-----------------------
pd1 | 3
pd4 | 1
pd2 | 1
desired result set =
product| count
-----------------------
pd1 | 3
pd4 | 1
pd2 | 1
Total | 5
Maybe you can add a UNION, and a SELECT with total amount. Something like this:
SELECT
product,
COUNT(OrderNumber) AS CountOf
FROM
orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
GROUP BY
product
UNION
SELECT 'Total', count(OrderNumber) AS CountOf
FROM orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
ORDER BY CountOf DESC;
Try using an Inner join on the same table, the union did not work due to there being the incorrect amount of columns on each side.
The Initial select had 2 set columns, where the second select (after the union) did not.
I am trying to find the number of sellers that made a sale last month but didn't make a sale this month.
I have a query that works but I don't think its efficient and I haven't figured out how to do this for all months.
SELECT count(distinct user_id) as users
FROM transactions
WHERE MONTH(date) = 12
AND YEAR(date) = 2015
AND transactions.status = 'COMPLETED'
AND transactions.amount > 0
AND transactions.user_id NOT IN
(
SELECT distinct user_id
FROM transactions
WHERE MONTH(date) = 1
AND YEAR(date) = 2016
AND transactions.status = 'COMPLETED'
AND transactions.amount > 0
)
The structure of the table is:
+---------+------------+-------------+--------+
| user_id | date | status | amount |
+---------+------------+-------------+--------+
| 1 | 2016-01-01 | 'COMPLETED' | 1.00 |
| 2 | 2015-12-01 | 'COMPLETED' | 1.00 |
| 3 | 2015-12-01 | 'COMPLETED' | 2.00 |
| 1 | 2015-12-01 | 'COMPLETED' | 3.00 |
+---------+------------+-------------+--------+
So in this case, users with ID 2 and 3, didn't make a sale this month.
Use conditional aggregation:
SELECT count(*) as users
FROM
(
SELECT user_id
FROM transactions
-- 1st of previous month
WHERE date BETWEEN SUBDATE(SUBDATE(CURRENT_DATE, DAYOFMONTH(CURRENT_DATE)-1), interval 1 month)
-- end of current month
AND LAST_DAY(CURRENT_DATE)
AND transactions.status = 'COMPLETED'
AND transactions.amount > 0
GROUP BY user_id
-- any row from previous month
HAVING MAX(CASE WHEN date < SUBDATE(CURRENT_DATE, DAYOFMONTH(CURRENT_DATE)-1)
THEN date
END) IS NOT NULL
-- no row in current month
AND MAX(CASE WHEN date >= SUBDATE(CURRENT_DATE, DAYOFMONTH(CURRENT_DATE)-1)
THEN date
END) IS NULL
) AS dt
SUBDATE(CURRENT_DATE, DAYOFMONTH(CURRENT_DATE)-1) = first day of current month
SUBDATE(first day of current month, interval 1 month) = first day of previous month
LAST_DAY(CURRENT_DATE) = end of current month
if you want to generify it, you can use curdate() to get current month, and DATE_SUB(curdate(), INTERVAL 1 MONTH) to get last month (you will need to do some if clause for January/December though):
SELECT count(distinct user_id) as users
FROM transactions
WHERE MONTH(date) = MONTH(DATE_SUB(curdate(), INTERVAL 1 MONTH))
AND transactions.status = 'COMPLETED'
AND transactions.amount > 0
AND transactions.user_id NOT IN
(
SELECT distinct user_id
FROM transactions
WHERE MONTH(date) = MONTH(curdate())
AND transactions.status = 'COMPLETED'
AND transactions.amount > 0
)
as far as efficiency goes, I don't see a problem with this one
The following should be pretty efficient. In order to make it even more so, you would need to provide the table definition and and the EXPLAIN.
SELECT COUNT(DISTINCT user_id) users
FROM transactions t
LEFT
JOIN transactions x
ON x.user_id = t.user_id
AND x.date BETWEEN '2016-01-01' AND '2016-01-31'
AND x.status = 'COMPLETED'
AND x.amount > 0
WHERE t.date BETWEEN '2015-12-01' AND '2015-12-31'
AND t.status = 'COMPLETED'
AND t.amount > 0
AND x.user_id IS NULL;
Just some input for thought:
You could create aggregated lists of user-IDs per month, representing all the unique buyers in that month. In your application, you would then simply have to subtract the two months in question in order to get all user-IDs that have only made a sale in one of the two months.
See below for query- and post-processing-examples.
In order to make your query efficient, I would recommend at least a 2-column index for table transactions on [status, amount]. However, in order to prevent the query from having to look up data in the actual table, you could even create a 4-column index [status, amount, date, user_id], which should further improve the performance of your query.
Postgres (v9.0+, tested)
SELECT (DATE_PART('year', t.date) || '-' || DATE_PART('month', t.date)) AS d,
STRING_AGG( DISTINCT t.user_id::TEXT, ',' ) AS buyers
FROM transactions t
WHERE t.status = 'COMPLETED'
AND t.amount > 0
GROUP BY DATE_PART('year', t.date),
DATE_PART('month', t.date)
ORDER BY DATE_PART('year', t.date),
DATE_PART('month', t.date)
;
MySQL (not tested)
SELECT (YEAR(t.date) || '-' || MONTH(t.date)) AS d,
GROUP_CONCAT( DISTINCT t.user_id ) AS buyers
FROM transactions t
WHERE t.status = 'COMPLETED'
AND t.amount > 0
GROUP BY YEAR(t.date), MONTH(t.date)
ORDER BY YEAR(t.date), MONTH(t.date)
;
Ruby (example for post-processing)
db_result = ActiveRecord::Base.connection_pool.with_connection { |con| con.execute( db_query ) }
unique_buyers = db_result.map{|e|[e['d'],e['buyers'].split(',')]}.to_h
buyers_dec15_but_not_jan16 = unique_buyers['2015-12'] - unique_buyers['2016-1']
buyers_nov15_but_not_dec16 = unique_buyers['2015-11']||[] - unique_buyers['2015-12']
...(and so on)...
I am trying to count achieve 3 results in one query:
Count all results where ‘app_creationdate’ = ('month') from current row
Count all results where ‘app_start’ = ('month') from current row
Count all results where ‘app_creationsdate’ < ‘app_start’ and ‘app_start’ = ('month') from current row
My Table:
app_id | app_creationdate(timestamp) | app_start(datetime)
00001 | 2014-11-17 19:39:04 | 2014-11-18 09:30:00
SELECT
DATE_FORMAT( app_creationsdate, '%m' ) AS 'month',
COUNT( app_id ) AS 'new',
(SELECT COUNT( app_id )
FROM appointments WHERE MONTH(app_start) = MONTH(NOW())) AS 'act',
(SELECT COUNT( app_id )
FROM appointments WHERE MONTH(app_creationsdate) < MONTH(app_start)) AS 'prev'
FROM appointments
WHERE app_owner = 2 AND app_creationsdate > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY DATE_FORMAT( app_creationsdate, '%Y%m' )
This may be closer to what you want. I'm still a bit confused about the prev scenario, so I did my best. I use EXTRACT(YEAR_MONTH FROM ...) to get the year and month, without the day, of each date so that we can do monthly comparisons. That's probably what you were trying to do with the DATE_FORMAT business.
SELECT DATE_FORMAT( app_creationsdate, '%m' ) AS 'month',
COUNT( app_id ) AS 'new',
-- get all other appointments that start in this month
(SELECT COUNT( act.app_id )
FROM appointments AS act
WHERE EXTRACT(YEAR_MONTH FROM act.app_start) = EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)) AS 'act',
-- get all appointments that were created before they started (???) and that started before this month
(SELECT COUNT( prev.app_id )
FROM appointments AS prev
WHERE EXTRACT(YEAR_MONTH FROM prev.app_creationsdate) < EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)
AND EXTRACT(YEAR_MONTH FROM prev.app_start) = EXTRACT(YEAR_MONTH FROM appointments.app_creationsdate)) AS 'prev'
FROM appointments
WHERE app_owner = 2
AND app_creationsdate > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY EXTRACT(YEAR_MONTH FROM app_creationsdate)
I am not entirely sure what you are trying to accomplish but I do notice one thing:
DATE_FORMAT(a2.app_start, '%m' ) = DATE_FORMAT('month', '%m' )
This: DATE_FORMAT('month', '%m' )...evaluates to NULL so equating that with anything is never going to work (I don't think anyway, but I'm new to MySQL... :) ).
Right now, I have a multiple select subquery that is grabbing data based on hour of the day that's a count. What I want to do now, is to introduce another table into that query, and count based on an id as well as the datetime in the original table.
What I have right now is:
select
(
select count(a_date)
from t1
where d_date
between '2013-01-07 00:00:00' and '2013-01-07 00:59:59'
) AS '00:00 to 00:59',
(
select count(a_date)
from t1
where d_date
between '2013-01-07 01:00:00' and '2013-01-07 01:59:59'
) AS '01:00 to 01:59'
and so on, till the end of the day.
I have another query that's giving me the count based on the id and datetime, but there's only two columns, one which is showing the c_name and the other showing the count for the hour.
Ex.
select t2.c_name, count(t1.a_date)
from t2 join t1
on t2.t1_key = t1.t2_key
where t1.d_date
between '2013-01-07 00:00:00' and '2013-01-07 00:59:59'
group by t2.c_id
Basically, I'd like to combine these two queries into one that can show the c_name and all of the hours of the day.
Any suggestions?
I would look into using the CASE statement.
Try something like this (adding your additional 23 columns):
select c_name,
SUM(case when HOUR(d_date) = 0 then 1 else 0 end) '00:00 to 00:59',
SUM(case when HOUR(d_date) = 1 then 1 else 0 end) '01:00 to 01:59'
from t2
join t1 on t2.t1_key = t1.t2_key
group by c_name
And here is the SQL Fiddle.
You just need to add your WHERE criteria for d_date -- something like:
where d_date between '2013-01-07 00:00:00' and '2013-01-07 23:59:59'
or
where Date(d_date) = '2013-01-07'
Good luck!