MySQL - select if no other entry on the same day - mysql

I am trying to get entry from a table, if "TIME" = 1 and no other events (entry) for same "UNIQ" occur on the same day.
The picture shows the data that should be selected...

SELECT *
FROM source t1
WHERE NOT EXISTS ( SELECT NULL
FROM source t2
WHERE t2.data >= DATE(t1.data)
AND t2.data < DATE(t1.data) + INTERVAL 1 DAY
AND t1.uniq = t2.uniq
AND t1.id != t2.id )
AND `time` = 1

SELECT * FROM `YOURTABLE`
WHERE TIME=1
AND UNIQ NOT IN (
SELECT UNIQ FROM `YOURTABLE`
WEHERE TIME=1
GROUP BY DATE(DATA)
having count(DATE(DATA)) > 1
)

Related

MySQL query add duration to previous record

I like to add event duration to a previous record every time a new record gets added.
This is what I have
ID EventType EventTime EventDuration
-------------------------------------
1 TypeA 10:20 NULL
2 TypeB 09:30 NULL
3 TypeC 08:00 NULL
This is what I want to achieve:
ID EventType EventTime EventDuration
-------------------------------------
1 TypeA 10:20 00:50
2 TypeB 09:30 01:30
3 TypeC 08:00 ...
4 ... ...
When a new records gets added (with ID, EventType and EventTime), the duration of the previous record (timediff between TypeB and Type A) should be added to the previous record in column EventDuration.
What I have so far is:
SELECT
id, EventTime,
timestampdiff(minute,
(SELECT EventTime
FROM TableName t2
WHERE t2.id < t1.id ORDER BY t2.id DESC LIMIT 1),EventTime)
AS EventDuration
FROM records t1
WHERE id = ....<this is where I get stuck, this should be a query that identifies the ID of latest EventTime record>
Any suggestions?
(I am running MySQL 5.6.39)
If you are running MySQL 8.0, you can use window functions for this:
update mytable t
inner join (
select id, timediff(eventTime, lag(eventTime) over(order by eventTime)) event_duration
from mytable t
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration
If you want to update only the last but 1 record, you can order by and limit in the subquery (or in the outer query):
update mytable t
inner join (
select id, timediff(eventTime, lag(eventTime) over(order by eventTime)) event_duration
from mytable t
order by id desc
limit 1, 1
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration
In earlier versions, one option is to emulate lag() with a window function:
update mytable t
inner join (
select
id,
timediff(
(select min(eventTime) from mytable t1 where t1.eventTime > t.eventTime),
eventTime
) event_duration
from mytable t
) t1 on t1.id = t.id
set t.event_duration = t1.event_duration

How can I select related items within the same table in one SQL query

I have a table looking like this:
id | date | related_id
1 2018-01-01
2 2018-01-01
3 2018-01-02
4 2018-01-05 2
5 2018-01-06
A query SELECT * FROM table WHERE date='2018-01-01' should produce the following result:
id | date | related_id
1 2018-01-01
2 2018-01-01
4 2018-01-05 2
How can I achieve that in one MySql query?
If you have only one "layer", you can do this:
SELECT t.*
FROM theTable AS t
LEFT JOIN theTable AS rt ON t.related_id = rt.id
WHERE t.`date` = searchValue OR rt.`date` = searchValue
;
If there are an indefinite number of layers, and you have MySQL 8.0, you can use a CTE:
WITH RECURSIVE myCte AS (
SELECT * FROM theTable WHERE `date` = searchValue
UNION
SELECT t.*
FROM theTable AS t
INNER JOIN myCTE ON t.related_id = myCTE.id
)
SELECT * FROM myCTE;
Disclaimer: I am more familiar with MS-SQL CTE's, so there could be some problems with that latter option.
Extend your WHERE condition to the related_id's date:
SELECT * FROM table t
WHERE
t.date = '2018-01-01'
OR
(SELECT date FROM table WHERE id = t.related_id) = '2018-01-01'
or with a self join:
SELECT t.*
FROM table t LEFT JOIN table tt
ON tt.id = t.related_id
WHERE
t.date = '2018-01-01'
OR
tt.date = '2018-01-01'
or with EXISTS:
SELECT t.*
FROM table t
WHERE
t.date = '2018-01-01'
OR
EXISTS (
SELECT 1 FROM table
WHERE id = t.related_id AND date = '2018-01-01'
)
You can use EXISTS :
SELECT t.*
FROM table t
WHERE t.date = '2018-01-01' OR
EXISTS (SELECT 1 FROM table t1 WHERE t.related_id = t1.id);
You can simply do this:
SELECT table.* FROM table LEFT JOIN table related
ON table.related_id = related.id
WHERE
table.date = '2018-01-01'
OR related.date = '2018-01-01';
this will work with the date function:
SELECT * FROM table WHERE date=DATE('2018-01-01');
or
SELECT * FROM table WHERE date=STR_TO_DATE(DATE, '%d/%m/%Y')

DB2 Show the latest row record from users, using the date and time

I have 100 records from 3 users. I want to show the most recent record from each user. I have the following query:
SELECT *
FROM Mytable
WHERE Dateabc = CURRENT DATE
AND timeabc =
(
SELECT MAX(timeabc)
FROM Mytable
)
It returns the most recent record for everyone, and I need it to return most recent record from every user.
Should the solution support both DB2 and mysql?
SELECT * FROM Mytable as x
WHERE Dateabc = CURRENT_DATE
AND timeabc = (SELECT MAX( timeabc ) FROM Mytable as y where x.user = y.user)
If it's only DB2 more efficient solutions exists:
SELECT * from (
SELECT x.*, row_number() over (partition by user order by timeabc desc) as rn
FROM Mytable as x
)
WHERE rn = 1
I assume somewhere in your table you have a userID...
select userID, max(timeabc) from mytable group by userID
SELECT *
FROM Mytable as a
WHERE Dateabc = CURRENT_DATE
AND timeabc =
(
SELECT MAX( timeabc )
FROM Mytable as b
WHERE a.uId = b.uId
)

Increment Multiple Timestamp Values

I have a table where i have a default value for the timestamp, e.g. 2013-06-15 12:00:00. There are at least 150 records with that value. Now I want to increment each of these timestamps by 1 second, taking into account that after 59 seconds, next value is next minute. Is this possible? Can you help? Thanks!
Here is another simple approach: (#kordirko, Thank you for your sqlfiddle)
SET #serial:=1;
UPDATE table1 SET t = t + INTERVAL (#serial:=#serial+1) SECOND;
You can test here. http://www.sqlfiddle.com/#!2/f5cbe/1
Assumming that the table has unique id column, this query can do this task:
UPDATE Table1 t1, (
SELECT t1.id, count(*) cnt
FROM table1 t1 JOIN table1 t2 ON t1.id >= t2.id
GROUP BY t1.id
) t2
SET t1.t = t1.t + interval t2.cnt second
WHERE t1.id = t2.id;
demo --> http://www.sqlfiddle.com/#!2/e6ef9b/1

mysql find date where no row exists for previous day

I need to select how many days since there is a break in my data. It's easier to show:
Table format:
id (autoincrement), user_id (int), start (datetime), end (datetime)
Example data (times left out as only need days):
1, 5, 2011-12-18, 2011-12-18
2, 5, 2011-12-17, 2011-12-17
3, 5, 2011-12-16, 2011-12-16
4, 5, 2011-12-13, 2011-12-13
As you can see there would be a break between 2011-12-13 and 2011-12-16. Now, I need to be able say:
Using the date 2011-12-18, how many days are there until a break:
2011-12-18: Lowest sequential date = 2011-12-16: Total consecutive days: 3
Probably: DATE_DIFF(2011-12-18, 2011-12-16)
So my problem is, how can I select that 2011-12-16 is the lowest sequential date? Remembering that data applies for particular user_id's.
It's kinda like the example here: http://www.artfulsoftware.com/infotree/queries.php#72 but in the reverse.
I'd like this done in SQL only, no php code
Thanks
SELECT qmin.start, qmax.end, DATE_DIFF( qmax.end, qmin.start ) FROM table AS qmin
LEFT JOIN (
SELECT end FROM table AS t1
LEFT JOIN table AS t2 ON
t2.start > t1.end AND
t2.start < DATE_ADD( t1.end, 1 DAY )
WHERE t1.end >= '2011-12-18' AND t2.start IS NULL
ORDER BY end ASC LIMIT 1
) AS qmax
LEFT JOIN table AS t2 ON
t2.end < qmin.start AND
t2.end > DATE_DIFF( qmin.start, 1 DAY )
WHERE qmin.start <= '2011-12-18' AND t2.start IS NULL
ORDER BY end DESC LIMIT 1
This should work - left joins selects one date which can be in sequence, so max can be fineded out if you take the nearest record without sequential record ( t2.anyfield is null ) , same thing we do with minimal date.
If you can calculate days between in script - do it using unions ( eg 1. row - minimal, 2. row maximal )
Check this,
SELECT DATEDIFF((SELECT MAX(`start`) FROM testtbl WHERE `user_id`=1),
(select a.`start` from testtbl as a
left outer join testtbl as b on a.user_id = b.user_id
AND a.`start` = b.`start` + INTERVAL 1 DAY
where a.user_id=1 AND b.`start` is null
ORDER BY a.`start` desc LIMIT 1))
DATEDIFF() show difference of the Two days, if you want to number of consecutive days add one for that result.
If it's not a beauty contents then you may try something like:
select t.start, t2.start, datediff(t2.start, t.start) + 1 as consecutive_days
from tab t
join tab t2 on t2.start = (select min(start) from (
select c1.*, case when c2.id is null then 1 else 0 end as gap
from tab c1
left join tab c2 on c1.start = adddate(c2.start, -1)
) t4 where t4.start <= t.start and t4.start >= (select max(start) from (
select c1.*, case when c2.id is null then 1 else 0 end as gap
from tab c1
left join tab c2 on c1.start = adddate(c2.start, -1)
) t3 where t3.start <= t.start and t3.gap = 1))
where t.start = '2011-12-18'
Result should be:
start start consecutive_days
2011-12-18 2011-12-16 3