Selecting multiple values within a timestamp interval - mysql

I have a (MySQL) table that looks like this:
`radiostation_id` varchar(36) NOT NULL,
`song_id` varchar(36) NOT NULL,
`date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`length` int(4) NOT NULL
What I want to do is to find every same song_id that has been played within an interval of 15 minutes. It could be that the song was played for example today 15:10 and then again 15:20. So it shouldnt be that i need to set the interval myself, it should check for any interval through the table and list all the songs and timestamps it happened.

It seems to me that you want a song that is played within a certain 15 minutes regardless of the day. There are date and time functions you can use to parse the information you want. For example, you can use TIME() to extract the time portion of your column. For example, you can search for any song played between 12:00 and 12:15 like this:
SELECT DISTINCT id
FROM myTable
WHERE TIME(timeColumn) BETWEEN '12:00:00' AND '12:15:00';
Here is a little SQL Fiddle I used to try it.
EDIT
Based on our discussions in the comments, you can use the following query. It will self join the table on the condition that the song_id matches (so you can compare individual songs), the condition that the time is not exactly the same (so no occurrence is counted twice) and on the condition that the interval in the second table is within +/- 15 minutes of the first like this:
SELECT m.song_id, m.timecolumn
FROM myTable m
JOIN myTable mt
ON m.song_id = mt.song_id
AND m.timeColumn != mt.timeColumn
AND mt.timeColumn BETWEEN DATE_SUB(m.timeColumn, INTERVAL 15 MINUTE) AND DATE_ADD(m.timeColumn, INTERVAL 15 MINUTE);
Here is an updated Fiddle.

It's not entirely clear what you are asking.
If you want to find occurrences of the same song_id, where a second row with the same song_id has a date value within 15 minutes of the first row, one way to get that would be a query like this:
SELECT t.song_id
FROM looks_like_this t
WHERE EXISTS ( SELECT 1
FROM looks_like_this s
WHERE s.song_id = t.song_id
AND s.date >= t.date
AND s.date <= t.date + INTERVAL 15 MINUTE
AND NOT (s.radiostation_id = t.radiostation_id AND s.date = t.date)
If you want to return a unique list of song_id, then add either DISTINCT keyword or a GROUP BY t.song_id clause.
Another way to get the result would be use a JOIN operation:
SELECT t.song_id
FROM looks_like_this t
JOIN looks_like_this s
ON s.song_id = t.song_id
AND s.date >= t.date
AND s.date <= t.date + INTERVAL 15 MINUTE
AND NOT (s.radiostation_id = t.radiostation_id AND s.date = t.date)
GROUP BY t.song_id

The following will show you all the rows where the last played is in the last 15 minutes.
SELECT * FROM myTable
WHERE date>= NOW() - INTERVAL 15 MINUTE
Note that using date in a table column is bad practice as it is a reserved mysql word.

You just need to list out all the songs, when they were played and connect to the same song if it was played again within 15 minutes later.
select pt1.ID, pt1.StartDate, pt2.StartDate StartDate2
from PlayTimes pt1
join PlayTimes pt2
on pt2.ID = pt1.ID
and pt2.StartDate > pt1.StartDate
and pt2.StartDate <= Date_Add( pt1.StartDate, interval 15 minute );
You didn't mention if the radio station played any role. The query above will return a song if it was play again within 15 minutes even on a different station. This makes sense. If you need only those songs played again within 15 minutes on the same station, then add the station id to the join criteria. Would a station ever do that (play the same song twice within 15 minutes)? Or are you checking to make sure a station never does that?

Related

How to fetch Aggregated result on every 3 hours in a specific date in MySQL?

I've the following table, And I'm trying to fetch total count of products in every 3 hours and Also I want to display 0 if no products exist under a certain period rather than displaying only existed records.
I'm closer and able get the records on every hour basis but not in the period of 3 hours. Please find the following queries I've used.
CREATE TABLE `integers` (
`i` int(11) NOT NULL,
PRIMARY KEY (`i`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `integers`(`i`) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21),(22),(23);
and
SELECT hr + INTERVAL 1 HOUR AS `date`, COUNT(products.product_id) AS product_count
FROM (
SELECT
FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(CURRENT_TIMESTAMP)/3600)*3600+1800) - INTERVAL i HOUR AS hr
FROM integers
WHERE i BETWEEN 0 AND HOUR(NOW())) AS times
LEFT OUTER JOIN product AS products
ON products.`updated_on` >= hr
AND products.`updated_on` < hr + INTERVAL 1 HOUR
AND products.`updated_on` > DATE(NOW())
GROUP
BY hr
ORDER
BY hr
With the above queries, I'm able to get the aggregated result for every 1 hour and the output as follows
But I want to make it to every 3 hour duration. I'm missing something somewhere and I'm not able to figure it out.
Try something like this (using modulo operator):
SELECT hr.i as hr_from,
hr.i + 3 as hr_to,
COUNT(p.product_id) AS product_count
FROM integers hr
LEFT OUTER JOIN product AS p
ON p.updated_on >= DATE(NOW())
AND HOUR(p.updated_on) BETWEEN hr.i and hr.i + 2
WHERE hr.i MOD 3 = 0
GROUP BY hr.i
ORDER BY hr.i

How to transform a NOT IN into a LEFT JOIN (or a NOT EXISTS)

I have the following query that is quite complex and even though I tried to understand how to do using various sources online, all the examples uses simple queries where mine is more complex, and for that, I don't find the solution.
Here's my current query :
SELECT id, category_id, name
FROM orders AS u1
WHERE added < (UTC_TIMESTAMP() - INTERVAL 60 SECOND)
AND (executed IS NULL OR executed < (UTC_DATE() - INTERVAL 1 MONTH))
AND category_id NOT IN (SELECT category_id
FROM orders AS u2
WHERE executed > (UTC_TIMESTAMP() - INTERVAL 5 SECOND)
GROUP BY category_id)
GROUP BY category_id
ORDER BY added ASC
LIMIT 10;
The table orders is like this:
id
category_id
name
added
executed
The purpose of the query is to list n orders (here, 10) that belong in different categories (I have hundreds of categories), so 10 category_id different. The orders showed here must be older than a minute ago (INTERVAL 60 SECOND) and never executed (IS NULL) or executed more than a month ago.
The NOT IN query is to avoid treating a category_id that has already been treated less than 5 seconds ago. So in the result, I remove all the categories that have been treated less than 5 seconds ago.
I've tried to change the NOT IN in a LEFT JOIN clause or a NOT EXISTS but the switch results in a different set of entries so I believe it's not correct.
Here's what I have so far :
SELECT u1.id, u1.category_id, u1.name, u1.added
FROM orders AS u1
LEFT JOIN orders AS u2
ON u1.category_id = u2.category_id
AND u2.executed > (UTC_TIMESTAMP() - INTERVAL 5 SECOND)
WHERE u1.added < (UTC_TIMESTAMP() - INTERVAL 60 SECOND)
AND (u1.executed IS NULL OR u1.executed < (UTC_DATE() - INTERVAL 1 MONTH))
AND u2.category_id IS NULL
GROUP BY u1.category_id
LIMIT 10
Thank you for your help.
Here's a sample data to try. In that case, there is no "older than 5 seconds" since it's near impossible to get a correct value, but it gives you some data to help out :)
Your query is using a column which doesn't exist in the table as a join condition.
ON u1.domain = u2.category_id
There is no column in your example data called "domain"
Your query is also using the incorrect operator for your 2nd join condition.
AND u2.executed > (UTC_TIMESTAMP() - INTERVAL 5 SECOND)
should be
AND u2.executed < (UTC_TIMESTAMP() - INTERVAL 5 SECOND)
as is used in your first query

Operation With SQL and Date

I'm a newbye in the operation with SQL on date.
However,I need to do a query that return record filter by X date < or > of 30 days or similar.
I have this query for now:
SELECT nome_prodotto,quantita
FROM prodotti
LEFT JOIN acquisti
ON prodotti.id_prodotto = acquisti.id_prodotto
my goal is get the product that aren't bought in last 30 days or similar
WHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) =< your_date;
If the date field in acquisti is called date_acquisti, products not bought in the last 30 days will be queried like this:
SELECT nome_prodotto,quantita
FROM prodotti
LEFT JOIN acquisti
ON (prodotti.id_prodotto = acquisti.id_prodotto
AND acquisti.date_acquisti > CURDATE() - INTERVAL 30 DAY)
where acquisti.id_prodotto is NULL
The trick is using the JOIN condition to get only the product acquisitions in the last 30 days. Since this is a LEFT JOIN, any row in result set where acquisti.id_prodotto is NULL means the product was not purchased in that period.
You can use date_add function to achieve this
Ex:
x_date between DATE_ADD(NOW(), INTERVAL -1 MONTH) and NOW()
Also,
where myDate between some_date and some_other_date
may help you in other similar situations.

Getting the newest record from a database Multiple queries

I have a mysql database with vehicles records. I need a fast query that will return the newest records of those records that were updated within the last 4 minutes. For example vehicle "A" may be updated several times a minute so it will appear many times within the last 4min. Same with vehicle B C etc. I need only the most recent entries for each vehicle within a 4 min window. I have tried like this
SELECT *
FROM yourtable AS a
WHERE a.ts =
(SELECT MAX(ts)
FROM yourtable AS b
WHERE b.ts > NOW() - INTERVAL 5 MINUTE
AND b.name = a.name)
but it takes too long to produce results >10seconds.
You don't need the self-join.
select max(ts), name from Table1
where ts > NOW() - INTERVAL 5 MINUTE
group by name
To get all the rows for the latest updates and not only the name and timestamp:
SELECT t.*
FROM
TableX AS t
JOIN
( SELECT name
, MAX(ts) AS maxts
FROM TableX
WHERE ts > NOW() - INTERVAL 4 MINUTE
GROUP BY name
) AS grp
ON grp.name = t.name
AND grp.maxts = t.ts
You'll need at least an index on the timestamp column for this query.

sql query to get duplicate records with different dates

I need to get records with different date field ,
table Sites:
field id
reference
created
Every day we add lot of records, so I need to do a function that extract all records existing with duplicates of rows just was added, to do some notifications.
the conditions that i can't get is the difference between records of the current day and the old data in the table should be (one day to 4 days) .
If is there any simple query to do that without using transaction .
I'm not sure I totally understand what you mean by duplicate records, but here's a basic date query:
SELECT fieldId, reference, created, DATE(created) as the_date
FROM Sites
WHERE the_date
BETWEEN DATE( DATE_SUB( NOW() , INTERVAL 3 DAY ) )
AND DATE ( NOW() )
I'm making several assumptions such as:
You don't want the "first" row returned
Duplicates don't carry the
date forward (The next after initial 4 days is not a duplicate)
The 4 days means +4 days so Day 5 is included
So, my code is :
with originals as (
select s1.*
from sites as s1
where 0 = (
select count(*)
from sites as s2
where s1.field_id = s2.field_id
and s1.reference = s2.reference
and s1.created <> s2.created
and DATEDIFF(DAY,s2.created, s1.created) between 1 and 4
)
)
select s1.*
from sites as s1
inner join originals as o
on s1.field_id = o.field_id
and s1.reference = o.reference
and s1.created <> o.created
where DATEDIFF(DAY,o.created, s1.created) between 1 and 4
order by 1,2,3;
Here it is in a fiddle: http://sqlfiddle.com/#!3/9b407/20
This could be simpler if some conditions are relaxed.
thanks a lot for every one who tried to help me ,
i have found this solution after lot of test
SELECT `id`,`reference`,count(`config_id`) as c,`created` FROM `sites`
where datediff(date(current_date()),date(`created`)) < 4
group by `reference`
having c > 1
thanks a lot for your help