Grouping based on current timestamp in sql - mysql

Okay So I have a df like this:
MEETING_ID sSTART
322 2021-05-01 23:45:00.000
322 2021-05-03 13:45:00.000
312 2021-05-11 23:45:00.000
312 2021-05-13 23:45:00.000
And all I want is a table that can tell me how many previous meetings have occurred and how many meetings are coming up...
To do this I use the CURRENT_TIMESTAMP function, unsure if this is wrong but here's my query that isnt working... For the purposes of this post let's say current time is 5/2/2021 10:40PM
WITH s AS (
SELECT MEETING_ID,
CASE WHEN sSTART > CURRENT_TIMESTAMP THEN 1
ELSE 0
END PREVIOUS_MEETING,
CASE WHEN sSTART < CURRENT_TIMESTAMP THEN 1
ELSE 0
END UPCOMING_MEETING
FROM df
),
ddd AS (SELECT
MEETING_ID,
COUNT(PREVIOUS_MEETING),
COUNT(UPCOMING_MEETING)
FROM s
GROUP BY MEETING_ID
)
SELECT *
FROM ddd
In the end I want this:
MEETING_ID PREVIOUS_MEETING UPCOMING_MEETING
322 1 1
312 2 0
I'm unsure why this is the case but some explanation would help.

You just want a basic pivot query here:
SELECT
MEETING_ID,
SUM(sSTART > CURRENT_TIMESTAMP) AS PREVIOUS_MEETING,
SUM(sSTART <= CURRENT_TIMESTAMP) AS CURRENT_MEETING
FROM df
GROUP BY
MEETING_ID;
Note that we are summing boolean expressions above, which is valid syntax in MySQL. On other databases, you might have to take conditional counts, something like this:
SELECT
MEETING_ID,
COUNT(CASE WHEN sSTART > CURRENT_TIMESTAMP THEN 1 END) AS PREVIOUS_MEETING,
COUNT(CASE WHEN sSTART <= CURRENT_TIMESTAMP THEN 1 END) AS CURRENT_MEETING
FROM df
GROUP BY
MEETING_ID;

Related

In mysql how to get users that have no event X in past 14 days and neither in the future

Consider I have the following table and current date is 2022-09-01:
Requirement: I want to get all users that have no event_name like cbt care in the past 14 days and onwards into the future.
I have this query:
SELECT * FROM test_table
WHERE event_name LIKE "%cbt care%"
AND start_date <= DATE_SUB(NOW(), INTERVAL 14 DAY)
;
Which returns:
The issue is that user_id = x does have a cbt care event in 2022-09-10 which is 9 days ahead of current date (2022-09-01).
How to return only users satisfy requirement posted above?
SELECT user_id,
COUNT(CASE WHEN event_name LIKE '%cbt care%' AND start_date
> CURDATE() - INTERVAL 14 day THEN 1 END) AS count_recent
FROM test_table
GROUP BY user_id
HAVING count_recent = 0;
https://www.db-fiddle.com/f/64j7L1VZsVdLYqmcQ2NrvV/0
The CASE expression returns 1 for each row with the conditions you described (a specific event name and a start date after the date 14 days ago, which includes all of the future dates too). For rows that don't match that condition, the CASE returns NULL. There's an implicit ELSE NULL in any CASE expression.
COUNT(<expr>), like many set functions, ignores NULLs. It will only count the occurrences of non-NULL values. So if the count returns 0, then the CASE returned only NULLs, which means there are no recent or future 'cbt care' events for that user.
select id
,user_id
,event_name
,start_date
from (
select *
,count(case when abs(datediff(curdate(),start_date)) <= 14 and event_name like "%cbt care%" then 1 end) over (partition by user_id) as cw
from t
) t
where cw = 0
id
user_id
event_name
start_date
0
a
cbt care
2022-06-01 20:00:00
Fiddle

Combining data from multiple rows into one

First question on here, so i will try my best to be clear.
I have 2 tables:
"TABLE1" which contains a record for each stock code and a list of attributes.
In TABLE 1 there is just one record for each stock_code
"TABLE2" which contains a log of changes to attributes of products, over time.
"TABLE2" contains the following fields:.
stock_code
stock_attribute
old_value
new_value
change_date
change_time
TABLE 2 has multiple entries ofr each stock_code.
Every time a stock item is change, another entry is made in Table2, with the attribute that has changed, the change date, time, old value and new value.
I want to create a query which will result in a table that has one record for each stock_code (from TABLE 1), and a column for each week over past year, with the value in each field being the last recorded "new_val" for that week (From TABLE 2)
I have tried
SELECT a.`stcode`, b.`week1`, b.`week2`, b.`week3`, b.`week4` etc. etc.
from (SELECT stcode, )as a
LEFT JOIN (SELECT stcode,
(CASE WHEN chngdate BETWEEN DATE_SUB(CURDATE(),INTERVAL 363 DAY) AND DATE_SUB(CURDATE(),INTERVAL 357 DAY) THEN newval END)week1,
(CASE WHEN chngdate BETWEEN DATE_SUB(CURDATE(),INTERVAL 356 DAY) AND DATE_SUB(CURDATE(),INTERVAL 350 DAY) THEN newval END)week2,
(CASE WHEN chngdate BETWEEN DATE_SUB(CURDATE(),INTERVAL 349 DAY) AND DATE_SUB(CURDATE(),INTERVAL 343 DAY) THEN newval END)week3,
(CASE WHEN chngdate BETWEEN DATE_SUB(CURDATE(),INTERVAL 342 DAY) AND DATE_SUB(CURDATE(),INTERVAL 336 DAY) THEN newval END)week4,
(etc
etc
etc
FROM (SELECT * from TABLE 2 ORDER BY "chngdate" DESC, "chngtime" DESC )as sub) as b ON b.stcode = s.stcode
ORDER BY stcode ASC
The trouble is with this, i get multiple lines for a stock_code which has mutliple entries....
for example, for stock_code abc123 the result i get is
STCODE WEEK1 WEEK2 WEEK3 WEEK4 WEEK5 WEEK6
abc123 null null 4 null null null
abc123 2 null null null null null
abc123 null null null null 3 null
what i WANT is this:
STCODE WEEK1 WEEK2 WEEK3 WEEK4 WEEK5 WEEK6
abc123 2 null 4 null 3 null
I have also tried the following, but teh query took so long, it never finished (there were 52 derived tables!)
SELECT a.`stcode`, w1.`new_value`, w2.`new_value`, w3.`new_value`, w4.`new_value` etc. etc.
from (SELECT stcode, )as a
LEFT JOIN (SELECT stcode,
LEFT JOIN (SELECT stcode, depot, fieldname, chngdate, chngtime, newval from STDepotAmendmentsLog WHERE chngdate BETWEEN DATE_SUB(CURDATE(),INTERVAL 363 DAY) AND DATE_SUB(CURDATE(),INTERVAL 357 DAY) ORDER BY "chngdate" DESC, "chngtime" DESC)as w1 on s.stcode = w1.stcode
etc for week 2, 3, 4 etc etc
You could do the following:
Find the greatest date for each "week"
Find the rows corresponding to those dates
Use conditional aggregation to convert rows into columns
Here is a rough outline of the code. It assumes that e.g. if today is 2020-03-03 then week 52 is from 2020-02-26 to 2020-03-03. Adjust if necessary:
SELECT t.stock_code
, MAX(CASE WHEN weeknum = 51 THEN new_value END) AS week01
, MAX(CASE WHEN weeknum = 50 THEN new_value END) AS week02
, MAX(CASE WHEN weeknum = 1 THEN new_value END) AS week51
, MAX(CASE WHEN weeknum = 0 THEN new_value END) AS week52
FROM table2 AS t
JOIN (
SELECT stock_code
, DATEDIFF(CURRENT_DATE, change_date) div 7 AS weeknum -- count multiples of 7
, MAX(change_date) AS greatest_date
GROUP BY stock_code, weeknum
FROM table2
) AS a ON t.stock_code = a.stock_code AND t.change_date = a.greatest_date
GROUP BY t.stock_code

Get sql data if have a specific value

I have this table :
id device createdAt type
1 700 2018-09-06 10:00:00 atos
2 700 2018-09-06 09:30:00 farkos
The idea is to verify if in last x hours I have in this table only data type = atos.
For that case I want to get a false as result. If this table will have only type = atos in last h hours the result expected should be true.
I tried like this and after that check with php but not very good idea (I want to do that in sql only) whitout additional treatment :
SELECT * FROM table t
WHERE t.device = 700
AND t.createdAt >= '2018-09-05 11:00:00'
This query will do what you want. It looks at all the entries in the time specified and if any of them is not atos, will return 0 (false). Otherwise it will return 1 (true).
SELECT MIN(CASE WHEN t.type != 'atos' THEN 0 ELSE 1 END)
FROM table1 t
WHERE t.device = 700 AND t.createdAt >= '2018-09-05 11:00:00'
If you want to check for the last h hours, change the WHERE clause to
WHERE t.device = 700 AND t.createdAt >= NOW() - INTERVAL h HOUR
Use case when:
SELECT deviceid,case when min(case when type='atos' then 1 else 0 end)=0 then false when min(case when type='atos' then 1 else 0 end)=1 then true end as val FROM table
t
WHERE t.device = 700
AND t.createdAt >= '2018-09-05 11:00:00'
group by deviceid

MySQL select field from one table with different conditions

I need your help with mysql query.
I have one table 'metrics':
create table metrics
(
guid binary(16) not null
primary key,
entry_guid binary(16) not null,
customer_guid binary(16) null,
metrics varchar(30) not null,
value int not null,
`_created` timestamp null,
`_updated` timestamp null
);
So, I'm trying to do something like this:
SELECT t1.entry_guid as entry_guid, SUM(t1.`value`) as last_week, SUM(t2.`value`) as last_month
FROM metrics as t1, metrics as t2
WHERE t1.`_created` > NOW() - INTERVAL 7 DAY OR t2.`_created` > NOW() - INTERVAL 1 MONTH
GROUP BY t1.entry_guid
But in result i get identical strange result of using SUM() function
entry_guid last_week last_month
1 4613 4613
2 207 207
3 6003 6003
4 9108 9108
Moreover result of SUM() func is strange, because I have only 300 rows and 'value' field in each row is equal 1, so max sum must be very little.
So, the query
SELECT t1.entry_guid as entry_guid, SUM(t1.`value`) as sum
FROM metrics as t1
GROUP BY t1.entry_guid
gives me
entry_guid sum
0x34303535636637643538396665633265 21
0x34313830656231666665393131326635 21
0x34336537663033653963303437356165 1
0x34363061653730313738313263386264 44
I need to get SUM('value') from one table, but with different conditions.
Can you show me how? Thank you in advance.
Use conditional aggregation:
SELECT m.entry_guid as entry_guid,
SUM(CASE WHEN m.`_created` > NOW() - INTERVAL 7 DAY THEN t1.`value` ELSE 0 END) as last_week,
SUM(CASE WHEN m.`_created` > NOW() - INTERVAL 1 MONTH THEN t2.`value` ELSE 0 END) as last_month
FROM metrics m
GROUP BY m.entry_guid;

What difference between

I have first query
select count(*)
from `order`
where marketer_id = 75 and
HandleStatus != -1 and
(Created_at BETWEEN '2017-05-01' AND '2017-05-31')
and result is 1050
i also have second query :
select count(*)
from `order`
where marketer_id = 75 and
HandleStatus != -1 and
(Month(Created_at) =5 and Year(Created_at) = 2017)
and result is 1111
I think 2 query have same meaning but it return 2 different result.
Info about column "Created_at": COLUMN_NAME Created_at, COLUMN_TYPE timestamp, IS_NULLABLE NO, COLUMN_KEY , COLUMN_DEFAULT CURRENT_TIMESTAMP
Please help what difference between 2 query?
If you consider the time within a day, the first query only returns results before 2017-05-31 00:00:00.
If you have any results after 2017-05-31 00:00:00 and before 2017-05-31 23:59:59 (maybe down to milliseconds too), they only show up in the second query.
The first query is not looking at 31st May, it looks only until 30 May. The absence of a time component means the time is taken as midnight, or the start of the 31st.
Between does take only up to '2017-05-30 23:59:59' and after 2017-05-01 00:00:00. It should not consider 31th full day.
If you want first query return same data as second query you can use like this
select count(*)
from `order`
where marketer_id = 75 and
HandleStatus != -1 and
(Created_at >= '2017-05-01' AND Created_at < '2017-06-01')