Multiple column counts by week - mysql

I have the following two tables:
Posts
post_id
post_title
post_timestamp
Comments
comment_id
posts_post_id
comment_content
comment_timestamp
I want to create a report that shows the weekly post count and comment count. Something like this:
Week StartDate Posts Comments
1 1/1/2012 100 305
2 1/8/2012 115 412
I have this query but it only pulls form the Posts table.
select makedate( left(yearweek(p.post_timestamp),1),week(p.post_timestamp, 2 ) * 7 ) as Week, COUNT(p.post_id) as Posts
FROM cl_posts p
GROUP BY Week
ORDER BY WEEK(p.post_timestamp)
How do I add the Comment count too?

I think you need something like this:
select
week(post_timestamp) as Week,
adddate(date(post_timestamp), INTERVAL 1-DAYOFWEEK(post_timestamp) DAY) as StartDate,
count(distinct post_id),
count(comment_id)
from
posts left join comments
on comments.posts_post_id = posts.post_id
group by Week, StartDate

Here is one way, using join:
select coalesce(p.week, c.week) as week, p.Posts, c.Comments
from (select makedate( left(yearweek(p.post_timestamp),1),week(p.post_timestamp, 2 ) * 7 ) as Week,
COUNT(*) as Posts
FROM cl_posts p
GROUP BY Week
) p full outer join
(select makedate( left(yearweek(c.comment_timestamp),1),week(c.comment_timestamp, 2 ) * 7 ) as Week,
COUNT(*) as Comments
FROM cl_comments c
GROUP BY Week
) c
on p.week = c.week
order by 1
The reason that I'm using a full outer join instead of another join type is to keep weeks even when one or the other counts are 0. The reason I'm not joining the tables together is because, presumably, you want the report by the comment date, not the post date of the post associated with the comment.

Related

Get distinct count of id in a set of days (on a particular date and previous 2 days)

I have 4 columns in my table, rii, uii, rdi and udi. Just like below:
+----------+------+----------+------+
| rdi| rii| udi| uii|
+----------+------+----------+------+
|2002-02-06|1376.Q|2002-02-06|1376.Q|
|2002-02-28|1376.Q|2002-02-28|1376.Q|
|2002-03-06|1376.Q|2002-03-06|1376.Q|
|2002-02-01|1792.T|2002-02-01|1792.T|
|2002-03-07|1802.T|2002-03-07|1802.T|
|2002-03-08|1802.T|2002-03-08|1802.T|
|2002-04-03|1802.T|2002-04-03|1802.T|
|2002-03-07|1805.T|2002-03-07|1805.T|
|2002-02-18|1810.T|2002-02-18|1810.T|
|2002-03-22|1821.T|2002-03-22|1821.T|
|2002-02-27|1862.T|2002-02-27|1862.T|
|2002-04-11|1878.T|2002-04-11|1878.T|
|2002-04-18|1884.T|2002-04-18|1884.T|
|2002-02-27|1899.T|2002-02-27|1899.T|
|2002-03-11|1924.T|2002-03-11|1924.T|
|2002-02-05|1925.T|2002-02-05|1925.T|
|2002-01-23|1926.T|2002-01-23|1926.T|
|2002-03-19|1926.T|2002-03-19|1926.T|
|2002-01-25|1942.T|2002-01-25|1942.T|
|2002-01-31|1942.T|2002-01-31|1942.T|
+----------+------+----------+------+
i just want to get the number of unique rii on a logic like if i give lookback as 2 then it should give unique number of rii in a set of days (on that particular rdi and in previous 2 days from rdi)
so i give the lookback as 2 then, my result should be like (for rdi = 2002-02-06, it should find the unique rii in rdi in (2002-02-06,2002-02-05,2002-02-04))
+----------+-------------+----------+------+
| rdi| rii| udi| uii|
+----------+-------------+----------+------+
|2002-02-06|1376.Q,1925.T|2002-02-06|1376.Q|
I tried with the below query, but not getting the required o/p
select count(distinct uii) as u,
rdi,
(select count(distinct rii) from `mytable` where rdi between DATE_SUB(rdi, INTERVAL 2 DAY) AND rdi) as r
from `mytable`
group by rdi
order by rdi;
check my fiddle here
You can use a LEFT JOIN to associate each record to records from previous days:
select t1.rdi,
group_concat(t2.rii) as rii,
t1.udi,
count(distinct t2.uii)
from `mytable` as t1
left join `mytable` as t2
on t2.rdi between DATE_SUB(t1.rdi, INTERVAL 2 DAY) AND t1.rdi
group by rdi
order by rdi;
Output:
Demo here

Find the value of one column based on maximum value in another column per group

I have a query which gives me three columns: an ID, the day of week of event and count of how many events each day of week has, i.e.
ID Day_Name Cnt
1 Thursday 1
2 Monday 3
2 Thursday 2
2 Sunday 2
3 Tuesday 7
3 Wednesday 3
I get this by using query
SELECT P.ID, DAYNAME(E.EVENT_DATE) AS Day_Name, COUNT(*) AS Cnt
FROM EVENT AS E
INNER JOIN PERSON AS P
ON P.ID_2 = E.ID_2
WHERE E.EVENT_DATE > '2016-01-01'
AND E.EVENT_STATUS LIKE '%OCCURED%'
GROUP BY P.ID, DAYNAME(E.EVENT_DATE)
I would like to reduce this query to only return the day of week for each user with the maximum count. At the same time, I would like to change the column with counts to instead show the frequency of events for that weekday. For the example above I would like to change the output to be
ID Day_Name Frequency
1 Thursday 1
2 Monday 0.429
3 Tuesday 0.7
Thankful if anyone got an idea
To get the expected result set you could do your calculation in outer query like
SELECT ID,
SUBSTRING_INDEX(GROUP_CONCAT(Day_Name ORDER BY Cnt DESC),',',1) Day_Name,
MAX(Cnt)/SUM(Cnt) Frequency
FROM(
SELECT P.ID, DAYNAME(E.EVENT_DATE) AS Day_Name, COUNT(*) AS Cnt
FROM EVENT AS E
INNER JOIN PERSON AS P
ON P.ID_2 = E.ID_2
WHERE E.EVENT_DATE > '2016-01-01'
AND E.EVENT_STATUS LIKE '%OCCURED%'
GROUP BY P.ID, DAYNAME(E.EVENT_DATE)
) t
GROUP BY ID
So here's a partial answer...
SELECT a.*
FROM ([your query here]) a
JOIN
( SELECT id,MAX(cnt) cnt FROM ([your query here]) GROUP BY id ) b
ON b.id = a.id
AND b.cnt = a.cnt;
For a more complete answer I suggest you provide the original 18 row data set. See: Why should I provide an MCVE for what seems to me to be a very simple SQL query?

How to add or substract minutes from a timediff result in mysql

I'm trying to make a query that will show all worked hours, days and persons.
I have that runnning.
Asume i have a table called uren:
rec_id | user_id | start (datetime) | eind (datetime)
and i have table called users
user_id | name |
With the query below i nearly have all the info i want.
select users.name, sec_to_time(SUM(TIME_TO_SEC(TIMEDIFF(uren.eind, uren.start)))),count(distinct(date(start))) as dagen
from uren, users
where date(uren.start) between CAST('2017-10-04 00:00:00' as Date) and CAST('2017-11-04 00:00:00' as DATE) and
uren.user_id = users.user_id
group by uren.user_id
ORDER BY name
Which shows me this
Piet (name) 230 (hours total) 24(days worked)
Now comes the real question:
I want to subtract 30 minutes for each day worked less then 5 hours.
Im clueless atm.
Can someonme please help
Assuming one row per user per day:
select users.name,
(sec_to_time(sum(time_to_sec(timediff(uren.eind, uren.start))) -
30 * 60 * sum(time_to_sec(timediff(uren.eind, uren.start)) < 5*60*60)
)
),
count(distinct(date(start))) as dagen
from uren join users
on uren.user_id = users.user_id
where date(uren.start) between '2017-10-04' and '2017-11-04'
group by uren.user_id
order by name;
If one day has multiple shifts, you need to aggregate by day first:
select u.name,
(sec_to_time(sum(day_secs) -
30 * 60 * sum(day_secs < 5*60*60)
)
),
count(*) as dagen
from (select uren.user_id, uren.name, date(uren.start),
sum(time_to_sec(timediff(uren.eind, uren.start))) as day_secs
from uren join
users
on uren.user_id = users.user_id
where uren.start >= '2017-10-04' and uren.start < '2017-11-05'
group by uren.user_id, date(uren.start)
) u
group by name
order by name
There is a good reason that you do not have a clue. It is because what you are asking is quite complex.
The first thing you need to accept (and I mean despairingly accept) is that your function depends days and users, and therefore, you need group by both, at first, then only by users in the final result. To do this, you will need a subquery that groups by days and users, before the parent can group by users.
Here is what I came up with...
SELECT
users.name,
sec_to_time(SUM(ur.timeWorked)) as tWorked,
SUM(ur.dagen) as Dagen
FROM users
INNER JOIN (
SELECT
user_id,
SUM(TIME_TO_SEC(TIMEDIFF(`eind`, `start`))) - (1800 *
IF(SUM(TIME_TO_SEC(TIMEDIFF(`eind`, `start`))) < 18000,1,0))
as `timeWorked`,
count(distinct(date(`start`))) as `dagen`
FROM uren
WHERE date(`start`)
BETWEEN CAST('2017-10-04 00:00:00' as Date)
AND CAST('2017-11-04 00:00:00' as DATE)
GROUP BY user_id, DAYOFYEAR(`start`)
) as ur ON ur.user_id = users.user_id
GROUP BY ur.user_id
ORDER BY name

Show most popular items of today?

I want to output all entries of today, sorted by the most popular entries (most likes = most popular).
I'm using this query which just selects the most popular entries in the past 24 hours, but if it's 0:00 o'clock for example the count should reset to zero. I also want to order alphabetically if entries have the same count-amount.
How could I achieve that? I tried to ORDER BY count DESC, p.id DESC but I think this didn't seem to work using GROUP BY I assume.
__
This is my code:
SELECT
p.id, COUNT(l.id) AS count, p.title_de, p.de
FROM
pages p
JOIN pages_likes l on l.page_id = p.id
WHERE
l.date >= DATE_SUB(NOW(),INTERVAL 1 DAY)
AND
l.`status` = 1 GROUP BY p.id
ORDER BY count DESC LIMIT 6
This outputs for example:
I guess you want count only the records from current day?
instead of
>= DATE_SUB(NOW(),INTERVAL 1 DAY)
Remove the time part with DATE()
SELECT DATE(NOW());
Now the order part: dont use reserved word for alias
SELECT
p.id,
COUNT(l.id) AS cnt, p.title_de, p.de
....
ORDER BY cnt DESC, p.title_de

mysql trying a select with multiple conditions

I have 2 tables with values like below:
tbl_users
user_ID name
1 somename1
2 somename2
3 somename3
tbl_interviews
int_ID user_ID answer date
1 1 sometextaba 2012-11-04
2 2 sometextxcec 2012-10-05
3 1 sometextabs 2011-06-04
4 3 sometextxcfc 2012-11-04
5 3 sometextxcdn 2012-11-04
how can i ask mysql tell me who is the only user in the table above that was interviewed this year but had also another interview in the previous years? the only one is the user with id = 1 (since he had an interview (the int_id 1) this year, but the first interview was in 2011 (int-id 3). )
unfortunately I'm not able even to select them..
By joining the table against itself, where one side of the join only includes interviews from this year and the other side only includes previous years, the result of the INNER JOIN will be users having both.
Because it doesn't need to rely on any aggregates or subqueries, this method should be extremely efficient. Especially so, if the date column has an index.
SELECT
DISTINCT
thisyear.user_ID,
name
FROM
/* Left side of join retrieces only this year (year=2012) */
tbl_interviews thisyear
/* Right side retrieves year < 2012 */
/* The combined result will elmininate any users who don't exist on both sides of the join */
INNER JOIN tbl_interviews previous_years ON thisyear.user_ID = previous_years.user_ID
/* and JOIN in the user table to get a name */
INNER JOIN tbl_users ON tbl_users.user_ID = thisyear.user_ID
WHERE
YEAR(thisyear.date) = 2012
AND YEAR(previous_years.date) < 2012
Here is a demonstration on SQLFiddle
A simple approach, perhaps less efficient than JOINs
SELECT DISTINCT user_ID
FROM tbl_interviews
WHERE user_ID IN (
SELECT user_ID
FROM tbl_interviews
WHERE date < 2012-01-01
)
AND user_ID IN (
SELECT user_ID
FROM tbl_interviews
WHERE date > 2012-01-01
)
Following gives you the users taking interviews in Current year, only those who also had appeared in some Previous year/s
SELECT Distinct tc.user_ID FROM tbl_interviews tc
INNER JOIN tbl_interviews tp ON tc.user_ID = tp.user_ID
WHERE YEAR(tc.date) = Year(curDate()) AND YEAR(tp.date) < Year(curDate());
SqlFiddle Demo
Here is a version with no joins, and only one subselect.
SELECT user_id
FROM (
SELECT user_id,
MAX(date) AS last_interview,
COUNT(int_id) AS interviews
FROM tbl_interviews
GROUP BY user_id) AS t
WHERE YEAR(last_interview) = 2012 AND interviews > 1
You can group tbl_interviews by user_id to count the number of interviews per user, and then filter for users who have more than one interview (in addition to having an interview this year). There a number of variations on this theme, according to your specific needs, so let me know if needs a tweak.
For example, this should work as well.
SELECT user_id
FROM (
SELECT user_id,
BIT_OR(YEAR(date) = 2012) AS this_year,
BIT_OR(YEAR(date) < 2012) AS other_year
FROM tbl_interviews
GROUP BY user_id) AS t
WHERE this_year AND other_year