how to get data weekly wise in mysql for each month - mysql

SELECT DATE_FORMAT(es.scheduled_datetime, '%X-%V') AS date,
COUNT(es.event_schedule_id) AS total,
0 as type
FROM event_schedule es ,event_schedule_mapping esm,events e
WHERE
es.event_schedule_id = esm.event_schedule_id and
esm.event_id = e.event_id and
es.event_status_id in(1,2) and
es.scheduled_datetime BETWEEN
'2017-01-01' AND '2017-01-31'
GROUP BY date
ORDER BY date
this is my Query using this Query i am able to display record whose count is greater than zero and below output come like this
for January month
'2017-01', '2', '0'
'2017-02', '2', '0'
'2017-03', '10', '0'
'2017-04', '2', '0'
'2017-05', '9', '0'
But its not displaying if count is zero in second week while i have to
display that also :
'2017-01', '2', '0'
'2017-02', '0', '0'
'2017-03', '10', '0'
'2017-04', '2', '0'
'2017-05', '9', '0'
please suggest me how to display Record if count is zero it should week wise please suggest me

if you want to get data weekly in each month from database , I have query for that try this query.
SELECT DISTINCT EXTRACT(WEEK FROM date) as week,tbl_data.date AS date, SUM(count.calories) AS sum,tbl_data.offset AS offset from tbl_data INNER JOIN count ON count.id = tbl_data.item_id where tbl_data.user_id="+user_id+" and tbl_data.date and MONTH(date) = MONTH(CURRENT_DATE()) GROUP BY week

Related

SQL multi query

I need some help to do it right in one query (if it possible).
(this is a theoretical example and I assume the presence of events in event_name(like registration/action etc)
I have 3 colums:
-user_id
-event_timestamp
-event_name
From this 3 columns we need to create new table with 4 new columns:
-user year and month registration time
-number of new user registration in this month
-number of users who returned to the second calendar month after registration
-return probability
Result must be looks like this:
2019-1 | 1 | 1 | 100%
2019-2 | 3 | 2 | 67%
2019-3 | 2 | 0 | 0%
What I've done now:
I'm use this toy example of my possible main table:
CREATE TABLE `main` (
`event_timestamp` timestamp,
`user_id` int(10),
`event_name` char(12)
) DEFAULT CHARSET=utf8;
INSERT INTO `main` (`event_timestamp`, `user_id`, `event_name`) VALUES
('2019-01-23 20:02:21.550', '1', 'registration'),
('2019-01-24 20:03:21.550', '2', 'action'),
('2019-02-21 20:04:21.550', '3', 'registration'),
('2019-02-22 20:05:21.550', '4', 'registration'),
('2019-02-23 20:06:21.550', '5', 'registration'),
('2019-02-23 20:06:21.550', '1', 'action'),
('2019-02-24 20:07:21.550', '6', 'action'),
('2019-03-20 20:08:21.550', '3', 'action'),
('2019-03-21 20:09:21.550', '4', 'action'),
('2019-03-22 20:10:21.550', '9', 'action'),
('2019-03-23 20:11:21.550', '10', 'registration'),
('2019-03-22 20:10:21.550', '4', 'action'),
('2019-03-22 20:10:21.550', '5', 'action'),
('2019-03-24 20:11:21.550', '11', 'registration');
I'm trying to test some queries to create 4 new columns:
This is for column #1, we select month and year from timestamp where action is registration (as I guess), but I need to sum it for month (like 2019-11, 2019-12)
SELECT DATE_FORMAT(event_timestamp, '%Y-%m') AS column_1 FROM main
WHERE event_name='registration';
For column #2 we need to sum users with even_name registration in this month for every month, or.. we can trying for searching first time activity by user_id, but I don't know how to do this.
Here is some thinks about it...
SELECT COUNT(DISTINCT user_id) AS user_count
FROM main
GROUP BY MONTH(event_timestamp);
SELECT COUNT(DISTINCT user_id) AS user_count FROM main
WHERE event_name='registration';
For column #3 we need to compare user_id with the event_name registration and last month event with any event of the second month so we get users who returned for the next month.
Any idea how to create this query?
This is how to calc column #4
SELECT *,
ROUND ((column_3/column_2)*100) AS column_4
FROM main;
I hope you will find the following answer helpful.
The first column is the extraction of year and month. The new_users column is the COUNT of the unique user ids when the action is 'registration' since the user can be duplicated from the JOIN as a result of taking multiple actions the following month. The returned_users column is the number of users who have an action in the next month from the registration. The returned_users column needs a DISTINCT clause since a user can have multiple actions during one month. The final column is the probability that you asked from the two previous columns.
The JOIN clause is a self-join to bring the users that had at least one action the next month of their registration.
SELECT CONCAT(YEAR(A.event_timestamp),'-',MONTH(A.event_timestamp)),
COUNT(DISTINCT(CASE WHEN A.event_name LIKE 'registration' THEN A.user_id END)) AS new_users,
COUNT(DISTINCT B.user_id) AS returned_users,
CASE WHEN COUNT(DISTINCT(CASE WHEN A.event_name LIKE 'registration' THEN A.user_id END))=0 THEN 0 ELSE COUNT(DISTINCT B.user_id)/COUNT(DISTINCT(CASE WHEN A.event_name LIKE 'registration' THEN A.user_id END))*100 END AS My_Ratio
FROM main AS A
LEFT JOIN main AS B
ON A.user_id=B.user_id AND MONTH(A.event_timestamp)+1=MONTH(B.event_timestamp)
AND A.event_name='registration' AND B.event_name='action'
GROUP BY CONCAT(YEAR(A.event_timestamp),'-',MONTH(A.event_timestamp))
What we will do is to use window functions and aggregation -- window functions to get the earliest registration date. Then some conditional aggregation.
One challenge is the handling of calendar months. To handle this, we will truncate the dates to the beginning of the month to facilitate the date arithmetic:
select yyyymm_reg, count(*) as regs_in_month,
sum( month_2 > 0 ) as visits_2months,
avg( month_2 > 0 ) as return_rate_2months
from (select m.user_id, m.yyyymm_reg,
max( (timestampdiff(month, m.yyyymm_reg, m.yyyymm) = 1) ) as month_1,
max( (timestampdiff(month, m.yyyymm_reg, m.yyyymm) = 2) ) as month_2,
max( (timestampdiff(month, m.yyyymm_reg, m.yyyymm) = 3) ) as month_3
from (select m.*,
cast(concat(extract(year_month from event_timestamp), '01') as date) as yyyymm,
cast(concat(extract(year_month from min(case when event_name = 'registration' then event_timestamp end) over (partition by user_id)), '01') as date) as yyyymm_reg
from main m
) m
where m.yyyymm_reg is not null
group by m.user_id, m.yyyymm_reg
) u
group by u.yyyymm_reg;
Here is a db<>fiddle.
Here you go, done in T-SQL:
;with cte as(
select a.* from (
select form,user_id,sum(count_regs) as count_regs,sum(count_action) as count_action from (
select FORMAT(event_timestamp,'yyyy-MM') as form,user_id,event_name,
CASE WHEN event_name = 'registration' THEN 1 ELSE 0 END as count_regs,
CASE WHEN event_name = 'action' THEN 1 ELSE 0 END as count_action from main) a
group by form,user_id) a)
select final.form,final.count_regs,final.count_action,((CAST(final.count_action as float)/(CASE WHEN final.count_regs = '0' THEN '1' ELSE final.count_regs END))*100) as probability from (
select a.form,sum(a.count_regs) count_regs,CASE WHEN sum(b.count_action) is null then '0' else sum(b.count_action) end count_action from cte a
left join
cte b
ON a.user_id = b.user_id and
DATEADD(month,1,CONVERT(date,a.form+'-01')) = CONVERT(date,b.form+'-01')
group by a.form ) final where final.count_regs != '0' or final.count_action != '0'

How to check values in mysql for preceeding rows and using them to find sum

I have to find the time, that the system that is based on this table has elapsed while having code '100', so firstly i thought that I have to find the newest row of the xID group and after that, check the previous rows if their code is 100, if so i have to proceed with previous previous row till it gets a 200 value, after that it finds the time from the following row of 200 hundred till now (value 100).
ID xID createdDate CODE
1 '1', '2019-07-27 11:52:01', '100'
2 '1', '2019-07-27 11:54:01', '200'
3 '2', '2019-09-03 05:10:02', '200'
4 '2', '2019-09-03 05:12:02', '200'
5 '3', '2019-09-02 05:12:02', '200'
6 '3', '2019-09-02 05:12:02', '100'
7 '3', '2019-09-02 05:12:02', '200'
8 '4', '2019-09-02 05:13:02', '200'
9 '5', '2019-09-03 05:10:03', '200'
10 '6', '2018-12-13 05:03:02', '200'
So this query must for each group of xID find the total time for which the system has been with code 100 until now. Hope I've been clear. And here is the sql so far.
select id, createdDate, code
from wlogs
where id in (
select max(id)
from wlogs
group by xid
)
order by xid;
EDIT:
MYSQL VERSION 8.0
RESULT must be something like this where the column totTimeWithCode100 must show the time in seconds or minutes doesn't matter, for each type of xID.
xID totTimeWithCode100
'1', '500'
'2', '2'
'3', '33'
'4', '200'
'5', '40'
'6', '200'
These rows
Prior to MySQL 8.0, we can use of user-defined variables (in a way that is unsupported) in carefully crafted SQL that takes advantage of behavior that is repeatably observed but not guaranteed. (The MySQL Reference Manual warns specifically about this usage of user-defined variables.)
Something like this:
SELECT s.xid AS `xID`
, IFNULL(SUM(s.secs_in_code100),0) AS `totTimeWithCode100`
FROM (
SELECT IF(#prev_xid = t.xid AND #prev_code = 100, TIMESTAMPDIFF(SECOND,#prev_date,t.createddate),0) AS secs_in_code100
, #prev_xid := t.xid AS xid
, #prev_date := t.createddate AS createddate
, #prev_code := t.code AS code
FROM ( SELECT #prev_xid := ''
, #prev_date := '1970-01-02 03:00'
, #prev_code := ''
) i
CROSS
JOIN wlogs t
ORDER
BY t.xid
, t.createddate
) s
GROUP BY s.xid
ORDER BY s.xid
With MySQL 8.0, we can avoid the user-defined variables by using analytic/window functions.
You can get the result you want by finding all the rows with CODE = 100 for a given xID that are immediately followed (in time) by a row with CODE != 100. This can be done by LEFT JOINing the rows with CODE != 100 to the preceding row if that row has CODE = 100:
SELECT w.xID, COALESCE(SUM(TIMESTAMPDIFF(SECOND, w1.createdDate, w2.createdDate)), 0) AS totTimeWithCode100
FROM (SELECT DISTINCT xID FROM wlogs) w
LEFT JOIN (SELECT *
FROM wlogs
WHERE CODE = 100) w1 ON w1.xID = w.xID
LEFT JOIN wlogs w2 ON w2.xID = w1.xID
AND w2.createdDate = (SELECT MIN(createdDate)
FROM wlogs w3
WHERE w3.xID = w1.xID AND
w3.createdDate > w1.createdDate)
GROUP BY w.xID
ORDER BY w.xID;
Demo on dbfiddle

How to get last record of each day in mysql?

I want to get last record of each day in mysql.Location<id, date, place_id> table has multiple entries on each day. This Location table has place_id and time at which place_id is inserted.
Also taking consider if place_id is not present then return second last record which has place_id. In following table for NULL, '2016-04-06 18:52:06' record we are returning '13664', '2016-04-06 12:57:30', which is second last record on '2016-04-06' (6th March) and has place_id.
One more thing, on single day, there would be more place_id, see the following table..
id || place_id || date
'1', '47', '2016-04-05 18:09:37'
'2', '48', '2016-04-05 12:09:37'
'3', '13664', '2016-04-06 12:57:30'
'4', '9553', '2016-04-08 10:09:37'
'5', NULL, '2016-04-06 18:52:06'
'6', '9537', '2016-04-07 03:34:24'
'7', '9537', '2016-04-07 03:34:24'
'8', '656', '2016-04-07 05:34:24'
'9', '7', '2016-04-07 05:34:57'
When I run following query it returns following result
Query I run the following query but it is giving me wrong result
`Location<id, place_id, date>`
select L1.place_id, L1.date from
Location1 L1
Left join
Location1 L2
on
Date(L1.date) = Date(L2.date)
And
L1.date < L2.date
where
L2.date is null
group by L1.date;
Result I want:
id....place_id ........date
'1', '47', '2016-04-05 18:09:37'
'3', '13664', '2016-04-06 12:57:30'
'4', '9553', '2016-04-08 10:09:37'
'9', '7', '2016-04-07 05:34:57'
You may give it a try:
SELECT
L.id,
L.place_id,
L.date
FROM Location L
INNER JOIN
(
SELECT
MAX(date) max_time
FROM Location
GROUP BY Date(`date`)
) AS t
ON L.date = t.max_time
SQL FIDDLE DEMO
SQL FIDDLE DEMO2
[Based on your expected output]
Can you try with the following query:
SELECT * FROM `Location` GROUP BY DATE(`date`) ORDER BY `date` DESC
What this query does is group the rows by descending date and show a row for each date.
Get the last record:
SELECT * FROM `Location` ORDER BY `date` LIMIT 1;
Get the last record that doesn't have a null as a value:
SELECT * FROM `Location` WHERE place_id IS NOT NULL ORDER BY `date` LIMIT 1;
Get records for all the places which are not null:
SELECT * FROM `Location` WHERE place_id IS NOT NULL GROUP BY `place_id` ORDER BY `date` DESC
Would this work?
select place_id, max(date) as MaxDate
from foo
where place_id is not NULL
group by place_id

MYSQL issue howto count result in master table not including all rows from a Detail table "labels" used in a join

To simplify the question I am only using a few field in my test table example
Master db
Id Description type cost
'1', 'Test1', '2', '100'
'2', 'Test2', '2', '100'
'3', 'Test3', '3', '100'
'4', 'Test4', '4', '100'
Labels db
ID Name Masterid
'1', 'Label1', '1'
'2', 'Label1', '2'
'3', 'Label2', '1'
'4', 'Label3', '1'
I would like to count all ID's and make summary for the cost field for all records in master containing label1 and label2 from labels
My Query
Select count(Distinct m.id) as andtall , sum(m.cost) as cost
from
master m
join labels l ON l.Masterid=m.id and l.name in ('Label1','Label2')
Since I am using Distinct in count that result will be correct, but Cost is wrong it's containg 3 records not 2.
'2', '300' I would like it to return 200 since only 2 records from master table should be returned.
Try this
SELECT
count( m.id ) as andtall,
sum( m.cost ) as cost
FROM
master m
JOIN (
SELECT
Masterid
FROM
labels l
WHERE
l.name in ('Label1', 'Label2')
GROUP BY master_id ) l ON l.Masterid = m.id

mysql group_concat order by utf8

I have the following problem
I have 3 table (all of the are used utf8 / utf8_general_ci encoding)
movies, channels, i also have 3 table movie_channels which
is just a combination of the other two with just 2 fields: movie_id,channel_id
here is my channels table (code,name)
'1', 'ОРТ'
'2', 'ТК Спорт'
'3', 'ТК ТНВ'
'4', 'НТВ'
'5', 'НТВ+'
'6', 'TSN'
here is my movie_channels table (movie _id, channel_id) channel_id references code field in channels table
'19', '2'
'19', '6'
'95', '1'
'95', '4'
'96', '1'
'96', '4'
'97', '1'
'97', '4'
'98', '1'
'98', '4'
'99', '1'
'99', '4'
'100', '1'
'100', '4'
don't mind quotes on id values. they are all ints of course, not chars, it's just pasting issue
for each movie i need to display comma separated list of channels
i used mysql group_concat
select t.movie_id,( select group_concat(c.name) from
movie_channels mc
join channels c on mc.channel_id=c.code
where mc.movie_id = t.movie_id
order by code desc )as audio_channel from movies t
but I dont like the order of concat for movie_id #19 i need the above sql to display TSN,ТК Спорт but it keeps returning me ТК Спорт,TSN . I tried to use order by code desc with no luck ,tried order by char_length(asc) with no success
any ideas ?
If for every movie you want to list all the channels that are showing that movie, you need something like this:
SELECT
mc.movie_id,
GROUP_CONCAT(c.name) AS channels
FROM movie_channels AS mc
JOIN channels AS c
ON c.code = mc.channel_id
GROUP BY mc.movie_id
ORDER BY c.code DESC;
You can add a ORDER BY clause inside the GROUP_CONCAT() aggregate to adjust the ordering of the grouped string.