This is my current query:
Select Month as ReqMonth1,
sum(TotalUsage) As ReqCount1,
sum(Memberbase) as Club_updates_Records1,
round(sum(TotalUsage)/sum(Memberbase)*100,0) AS UsagePerc
from(
Select * from (
SELECT
CAST(DATE_FORMAT(Log_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Log_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Log_date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club}
GROUP BY
CAST(DATE_FORMAT(Log_Date, '%M-%y') AS CHAR(100)) ) as A
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%y-%m') AS CHAR(100)) AS 'Monthsort',
0 AS TotalUsage,
ifnull(max(Club_updates.`Records`),1) AS MemberBase
FROM
`Club updates` Club_updates
WHERE
cast(Club_updates.`Update_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Club_updates.`fk_Club` = $P{Club}
GROUP BY CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%M-%y') AS CHAR(100)) ) As B) as D
group by Month
Order by MonthSort
I'm trying to replicate/add another sub query "A" with the change on the Close_Date field instead of the Log_Date field in the WHERE clause.
Basically resulting a sum of both subqueries only in the "ReqCount1" field.
Any help would be appreciated.
Ok, got it solved
here's the solution(with an additional condition in the WHERE clause)
Select Month as ReqMonth1,
sum(TotalUsage) As ReqCount1,
sum(Memberbase) as Club_updates_Records1,
round(sum(TotalUsage)/sum(Memberbase)*100,0) AS UsagePerc
from(
Select * from (
SELECT
CAST(DATE_FORMAT(Log_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Log_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Log_date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club} AND Requests.`Request_Type` <> 7
GROUP BY
CAST(DATE_FORMAT(Log_Date, '%M-%y') AS CHAR(100)) ) as A
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Close_Date, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Close_Date, '%y-%m') AS CHAR(100)) AS 'Monthsort',
count(Requests.`fk_Members_ID`) AS TotalUsage,
0 as Memberbase
FROM
`Requests` Requests INNER JOIN `Members` Members ON Requests.`fk_Members_ID` = Members.`ID`
WHERE
cast(Requests.`Close_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Members.`Club` = $P{Club} AND Requests.`Request_Type` = 7
GROUP BY
CAST(DATE_FORMAT(Close_Date, '%M-%y') AS CHAR(100)) ) as G
UNION ALL
Select * from (
SELECT
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%b-%y') AS CHAR(100)) AS 'Month',
CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%y-%m') AS CHAR(100)) AS 'Monthsort',
0 AS TotalUsage,
ifnull(max(Club_updates.`Records`),1) AS MemberBase
FROM
`Club updates` Club_updates
WHERE
cast(Club_updates.`Update_Date` as date) BETWEEN date_sub(if($P{StartDate}>'2016-06-01',$P{StartDate},'2016-05-01'), Interval 4 month) and $P{EndDate} AND $P{EndDate}
AND Club_updates.`fk_Club` = $P{Club}
GROUP BY CAST(DATE_FORMAT(Club_updates.`Update_Date`, '%M-%y') AS CHAR(100)) ) As B) as D
group by Month
Order by MonthSort
Related
I have Query 1
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) ) as x
Returns 18
Query 2
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) having cnt=31) as x
Return 6
I want the ratio of query 1 and two. Means
18/6 . I am using MySQL
If you use both queries as CTEs, then it becomes relatively simple:
WITH q1
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME))),
q2
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME)
HAVING cnt = 31))
SELECT q1.total_daily_active_user_group_month /
q2.total_daily_active_user_group_month
AS result
FROM dual;
You commented that you got an error pointing to the WITH keyword; switch to two subqueries, then; simplified:
select a.value / b.value as result
from (select count(distinct user_id) value
from ... your 1st query goes here
) a,
(select count(distinct user_id) value
from ... your 2nd query goes here
) b;
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
I'm doing this select statement:
SELECT * FROM (
SELECT COUNT(t.text) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE1 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart) as t
UNION ALL
SELECT * FROM (
SELECT COUNT(b.id) as count, COUNT(DISTINCT(b.from_user_id)) as usercount, DATE_FORMAT(b.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE2 b WHERE b.created_at >= '2015-08-12 00:00:00' AND b.created_at <= '2015-08-13 18:30:00' AND b.eliminar IS NULL
GROUP BY datepart) as x GROUP BY datepart
this select gets this:
I'm trying to view with datepart grouped but I can't, any idea what I'm doing wrong?
TABLE2 only have (id,from_user_id,eliminar) and all are NULL except created_at, in this row I have entire 2015 year by day and hour, same format as TABLE1
SOLVED:
SELECT DISTINCT * FROM (
SELECT COUNT(t.text) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE1 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart
UNION ALL
SELECT COUNT(t.id) as count, COUNT(DISTINCT(t.from_user_id)) as usercount, DATE_FORMAT(t.created_at,'%Y-%m-%d %H:00') datepart
FROM TABLE2 t WHERE t.created_at >= '2015-08-12 00:00:00' AND t.created_at <= '2015-08-13 18:30:00' AND t.eliminar IS NULL
GROUP BY datepart) as x GROUP BY datepart ORDER BY datepart
For some calculations I need the sum of some table entries for the last 30 days. My idea is to do something like:
SELECT
a.`date`,
(SELECT COUNT(*) FROM `subtable1` AS b WHERE b.`date` = a.`date`) AS `sum1`,
(SELECT COUNT(*) FROM `subtable2` AS c WHERE c.`date` = a.`date`) AS `sum2`,
(SELECT COUNT(*) FROM `subtable3` AS d WHERE d.`date` = a.`date`) AS `sum2`
FROM
("31.05.2013", "30.05.2013", "29.05.2013") AS `date`
But I cant figure out the correct syntax to do this. Is it even possible? And if yes, how?
Try this:
SELECT
`date`,
SUM(IF(za_type=1,nb,0)) as sum1,
SUM(IF(za_type=2,nb,0)) as sum2,
SUM(IF(za_type=3,nb,0)) as sum3
FROM (
SELECT b.`date`,1 as za_type, COUNT(*) as nb FROM `subtable1` AS b WHERE b.`date` IN ('31-05-2013','30-05-2013','29-05.2013') UNION
SELECT c.`date`,2 as za_type, COUNT(*) as nb FROM `subtable2` AS c WHERE c.`date` IN ('31-05-2013','30-05-2013','29-05.2013') UNION
SELECT d.`date`,3 as za_type, COUNT(*) as nb FROM `subtable3` AS d WHERE d.`date` IN ('31-05-2013','30-05-2013','29-05.2013')
) as tmp
GROUP BY
`date`
UPDATE: if you need for the last 30 days you can add this condition date >= NOW() - INTERVAL 30 DAY instead of date IN (..)
UPDATE2: using new requirement (the query is for the last 3 days):
SELECT
za_day,
(SELECT COUNT(*) FROM subtable1 s WHERE s.date = za_day) as sum1,
(SELECT COUNT(*) FROM subtable2 s WHERE s.date = za_day) as sum2,
(SELECT COUNT(*) FROM subtable3 s WHERE s.date = za_day) as sum3
FROM (
SELECT DATE(NOW()) - INTERVAL 1 DAY as za_day UNION
SELECT DATE(NOW()) - INTERVAL 2 DAY as za_day UNION
SELECT DATE(NOW()) - INTERVAL 3 DAY as za_day
) as td
The tip to use UNION from #Vivek brought on the right way. The solution is:
SELECT
`current_date`,
(SELECT COUNT(*) FROM `subtable1` AS b WHERE b.`date` = `current_date`) AS `sum1`,
(SELECT COUNT(*) FROM `subtable2` AS c WHERE c.`date` = `current_date`) AS `sum2`,
(SELECT COUNT(*) FROM `subtable3` AS d WHERE d.`date` = `current_date`) AS `sum3`
FROM
(
SELECT "31.05.2012" AS `current_date`
UNION SELECT "30.05.2012" AS `current_date`
UNION SELECT "29.05.2012" AS `current_date`
) AS `dates`
Edit
So, the final query looks like this and counts all ad clicks, ad impressions and some other stuff for the last 30 days (the timestamps are generated by some php code).
SELECT
`current_timestamp`,
(
SELECT
COUNT(*)
FROM
`ad_clicks` AS a
WHERE
FLOOR(a.`timestamp` / 86400) * 86400 = `current_timestamp`
) AS `ad_click_count`,
(
SELECT
COUNT(*)
FROM
`ad_impressions` AS b
WHERE
FLOOR(b.`timestamp` / 86400) * 86400 = `current_timestamp`
) AS `ad_impression_count`,
(
SELECT
COUNT(*)
FROM
`stand_touches` AS c
WHERE
FLOOR(c.`timestamp` / 86400) * 86400 = `current_timestamp`
) AS `stand_touch_count`,
(
SELECT
COUNT(*)
FROM
`stand_url_clicks` AS d
WHERE
FLOOR(d.`timestamp` / 86400) * 86400 = `current_timestamp`
) AS `stand_url_call_count`
FROM
(
SELECT "1369958400" AS `current_timestamp` UNION
SELECT "1369872000" AS `current_timestamp` UNION
SELECT "1369785600" AS `current_timestamp` UNION
SELECT "1369699200" AS `current_timestamp` UNION
SELECT "1369612800" AS `current_timestamp` UNION
SELECT "1369526400" AS `current_timestamp` UNION
SELECT "1369440000" AS `current_timestamp` UNION
SELECT "1369353600" AS `current_timestamp` UNION
SELECT "1369267200" AS `current_timestamp` UNION
SELECT "1369180800" AS `current_timestamp` UNION
SELECT "1369094400" AS `current_timestamp` UNION
SELECT "1369008000" AS `current_timestamp` UNION
SELECT "1368921600" AS `current_timestamp` UNION
SELECT "1368835200" AS `current_timestamp` UNION
SELECT "1368748800" AS `current_timestamp` UNION
SELECT "1368662400" AS `current_timestamp` UNION
SELECT "1368576000" AS `current_timestamp` UNION
SELECT "1368489600" AS `current_timestamp` UNION
SELECT "1368403200" AS `current_timestamp` UNION
SELECT "1368316800" AS `current_timestamp` UNION
SELECT "1368230400" AS `current_timestamp` UNION
SELECT "1368144000" AS `current_timestamp` UNION
SELECT "1368057600" AS `current_timestamp` UNION
SELECT "1367971200" AS `current_timestamp` UNION
SELECT "1367884800" AS `current_timestamp` UNION
SELECT "1367798400" AS `current_timestamp` UNION
SELECT "1367712000" AS `current_timestamp` UNION
SELECT "1367625600" AS `current_timestamp` UNION
SELECT "1367539200" AS `current_timestamp` UNION
SELECT "1367452800" AS `current_timestamp`
) AS `timestamps`
You could setup a temporary table and fill it with the data you wanted.
Then you can join your present tables with the temporary one as you like.
Hi all i execute this query to get a table where there's statistics of some database information.. i'd like to intialise the fields that don't exist ( because the query is executed in different dates and sometimes there's a day where there's nothing ) so i'd like it to return 0 and NULL ( in TOP column )
SELECT
SUM(IF(`TOP` = 'one',`Nb`,0)) as first_one,
SUM(IF(`TOP` = 'two',`Nb`,0)) as second_one,
SUM(IF(`TOP` = 'three',`Nb`,0)) as thrid_one,
SUM(IF(`TOP` NOT IN ('three','two','one'),`Nb`,0)) as forth_one,
GROUP_CONCAT(IF(`TOP` NOT IN ('three','two','one'),`TOP`,'') SEPARATOR '') as `OR`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'two' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S=0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
COUNT(*) as Nb,
'three' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND S<>0
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
UNION ALL
SELECT
`Nb`,
`TOP`
FROM(
SELECT
COUNT(*) as Nb ,
`OR` as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
GROUP BY
`OR`
ORDER BY
Nb DESC
LIMIT 1
) as tmp
)as tmp1
Assuming that in tmp1 you have data you need but with "gaps" (days when there were no data at all) you could RIGHT JOIN tmp1 to table tmp2 using day (I assume that you have such column in tmp1 table). So tmp2 would be just list of days:
SELECT '2013-05-17' as day UNION SELECT '2013-05-18' UNION SELECT ...
I could elaborate my answer if you'd like to provide your DB schema.
You can replace each subquery with:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'value') as `TOP`
FROM (
--subquery
) as tmp
Example for the first subquery:
SELECT
IFNULL(tmp.Nb,0) as Nb,
IFNULL(tmp.`TOP`, 'one') as `TOP`
FROM (
SELECT
COUNT(*) as Nb,
'one' as `TOP`
FROM
mytable
WHERE
TYPE = 'MSS'
AND YEAR(date) = YEAR(CURDATE())
AND MONTH(date) = MONTH(CURDATE())
) as tmp
SQL is good at grouping existing entities into categories, but bad at "creating" entities itself. I would advise either a generic number table (really just the numbers from 0 to a few hundredthousand) if you have also non-date categories or as Wiktor suggested a date-Table which gets filled every now and then and has the next few years as well as the time since your program is working.
With a date table
list_dates (
id int(11) not null primary key auto_increment,
dateval date not null
)
you could start your queries from that table (with a reasonable range, of course) and count every thing else:
select list_dates.dateval as date, count(*) as cnt
from list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;
or starting with a number table numbers
select $fromDate + interval numbers.number day as date, count(*) as cnt
from numbers
left join actions
on actions.actiontime >= (cast $fromDate + interval numbers.number day as datetime)
and actions.actiontime < (cast $fromDate + interval (1 + numbers.number) day as datetime)
where numbers.number >= 0 and numbers.number < $countDates
group by numbers.number
;
One Day
If you really want just that one day (today) then you can of course use a anonymous subselect- Table instead, so it becomes
select list_dates.dateval as date, count(*) as cnt
from ( select curdate() as dateval ) as list_dates
left join actions on actions.actiontime >= (cast list_dates.date_val as datetime)
and actions.actiontime < (cast list_dates.date_val `interval 1 day as datetime)
where list_dates.dateval between '$fromDate' and '$toDate'
group by list_dates.dateval
;