Essentially, I want to find out how much time is spent on a product.
Each product is identified by the model_id and different people may work on
each product. I want the time difference between when the product is being worked on and when there is more than a 5 minute gap.
example table
CREATE TABLE test (id INT, created_at DATETIME, model_id INT, TIMEDIFF DATETIME, TOTALTIME DATETIME)
SELECT '144111', '2019-03-30 11:14:26','301302','',''
UNION
SELECT '144112', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144113', '2019-03-30 11:14:33','301302','',''
UNION
SELECT '144114', '2019-03-30 11:14:54','301302','',''
UNION
SELECT '144115', '2019-03-30 11:15:35','301302','',''
UNION
SELECT '144116', '2019-03-30 11:22:21','301302','',''
UNION
SELECT '144117', '2019-03-30 11:23:14','301302','',''
UNION
SELECT '144118', '2019-03-30 11:24:24','301302','',''
UNION
SELECT '144119', '2019-03-30 11:25:35','301302','',''
my attempt
WHILE (SELECT COUNT(model_id) FROM portal3_projectsolar.`qat_` WHERE `timediff` IS NULL) > 0 DO #begining of while loop
#min modelid
SET #modelid = (SELECT MIN(model_id) FROM `portal3_projectsolar`.`qat_` WHERE `Timediff` IS NULL);
#set the times
SET #starttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #endtime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #starttime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` a WHERE a.model_id = #modelid AND a.created_at > #endtime AND a.`Timediff` IS NULL ORDER BY a.model_id, a.created_at);
# compare the endtime and the nexttime. if nextime is 5 minutes more than endtime then endtime is endtime
WHILE (SELECT DATE_ADD(#endtime,INTERVAL 30 MINUTE) > #Nextdate) DO
SET #Endtime =(SELECT #Nexttime);
SET #Nexttime = (SELECT MIN(created_at) FROM `portal3_projectsolar`.`qat_` WHERE model_id = #modelid AND created_at > #endtime AND `Timediff` IS NULL ORDER BY model_id, created_at);
END WHILE;
#the time diffrence
SET #timediff = (SELECT TIMESTAMPDIFF(MINUTE, #starttime, #endtime));
SET #startid = (SELECT MIN(id) FROM qat_ WHERE created_at = #starttime);
SET #endid = (SELECT MIN(id) FROM qat_ WHERE created_at = #endtime);
#update the time diff for the id range
UPDATE portal3_projectsolar.`qat_`
SET `timediff` = #timediff
WHERE Created_at = BETWEEN #starttime AND #Endtime;
END WHILE;
The results should show the difference of the start and end in the timediff column and the total time spent for each model_id in the totaltime column
Related
I have table like
SELECT id, name, date FROM `table` ORDER BY `date` DESC, id DESC
...
10 |a|2020-01-08 20:40:00
9 |b|2020-01-08 20:40:00
8 |c|2020-01-08 20:40:00
500 |d|2020-01-06 22:49:00
7 |e|2020-01-06 22:00:00
...
How to get next and previous of a record. (ex: i have info of a record with id = 8 then how to get a next record is 9 and a previous record is 500)
Method #1 (requires MySQL 8+):
SQL
-- Previous ID
WITH cte_desc AS (SELECT * FROM `table` ORDER BY `date` DESC, id DESC),
cte_r AS (SELECT * FROM `table` WHERE id = #r_id)
SELECT id AS prev_id
FROM cte_desc
WHERE `date` < (SELECT `date` FROM cte_r)
OR `date` = (SELECT `date` FROM cte_r) AND id < (SELECT id FROM cte_r)
LIMIT 1;
-- Next ID
WITH cte_asc AS (SELECT * FROM `table` ORDER BY `date`, id),
cte_r AS (SELECT * FROM `table` WHERE id = #r_id)
SELECT id AS next_id
FROM cte_asc
WHERE `date` > (SELECT `date` FROM cte_r)
OR `date` = (SELECT `date` FROM cte_r) AND id > (SELECT id FROM cte_r)
LIMIT 1;
where #r_id is set to the ID of the row you want to find the previous/next for = 8 in your example.
Explanation
Two Common Table Expressions are defined: cte_desc sorts the table and cte_r gets the current row. The query part then finds the top row for which either the date value is strictly less than that of the chosen row or for which it is equal but the id is strictly less.
Online Demo
Dbfiddle demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=5380e374f24243d578db28b9f89b9c8c
Method #2 (for earlier MySQL versions)
Similar to above - just slightly longer when there is no CTE support:
SQL
-- Previous ID
SELECT id AS prev_id
FROM (SELECT * FROM `table` ORDER BY `date` DESC, id DESC) sub
WHERE `date` < (SELECT `date` FROM `table` WHERE id = #r_id)
OR `date` = (SELECT `date` FROM `table` WHERE id = #r_id)
AND id < (SELECT id FROM `table` WHERE id = #r_id)
LIMIT 1;
-- Next ID
SELECT id AS next_id
FROM (SELECT * FROM `table` ORDER BY `date`, id) sub
WHERE `date` > (SELECT `date` FROM `table` WHERE id = #r_id)
OR `date` = (SELECT `date` FROM `table` WHERE id = #r_id)
AND id > (SELECT id FROM `table` WHERE id = #r_id)
LIMIT 1;
Online Demo
Rextester demo: https://rextester.com/MTW78358
Method #3 (Slower? See first comments):
-- Previous ID
SELECT id AS prev_id
FROM `table`
WHERE CONCAT(`date`, LPAD(id, 8, '0')) =
(SELECT MAX(CONCAT(`date`, LPAD(id, 8, '0')))
FROM `table`
WHERE CONCAT(`date`, LPAD(id, 8, '0')) < (SELECT CONCAT(`date`, LPAD(id, 8, '0'))
FROM `table`
WHERE id = #r_id));
-- Next ID
SELECT id AS next_id
FROM `table`
WHERE CONCAT(`date`, LPAD(id, 8, '0')) =
(SELECT MIN(CONCAT(`date`, LPAD(id, 8, '0')))
FROM `table`
WHERE CONCAT(`date`, LPAD(id, 8, '0')) > (SELECT CONCAT(`date`, LPAD(id, 8, '0'))
FROM `table`
WHERE id = #r_id));
Online Demo
Rextester demo: https://rextester.com/BSQQL24519
Explanation
The ordering is by date/time then by ID so to simplify the searching, these are concatenated into a single string - but there is the usual snag of a string ordering placing e.g. 10 after 1 rather than after 9. To overcome this, the IDs are padded with zeros up to the number of digits of the maximum integer in MySQL (4294967295) - using the LPAD function. Having done this groundwork, the previous row can then be found by looking for the largest one that is less than the one for the current id value using MAX and a subselect.
You will need to find first of all, current record's position available in the current ordered list, then you will be able to find the previous record as well as next record.
PREVIOUS RECORD
SELECT row_number, id,name,`date`
FROM (
SELECT #row := #row + 1 AS row_number, id,name,`date`
FROM `table` AS t
JOIN (SELECT #row := 0) r
ORDER BY `date` DESC, id DESC
) main
WHERE row_number = (
SELECT current_row - 1
FROM (
SELECT #curRow := #curRow + 1 AS current_row, t.id,t.name,t.`date`
FROM `table` AS t
JOIN (SELECT #curRow := 0) r
ORDER BY `date` DESC, id DESC
) t1
WHERE id = 8
);
NEXT RECORD
SELECT row_number, id,name,`date`
FROM (
SELECT #row := #row + 1 AS row_number, id,name,`date`
FROM `table` AS t
JOIN (SELECT #row := 0) r
ORDER BY `date` DESC, id DESC
) main
WHERE row_number = (
SELECT current_row + 1
FROM (
SELECT #curRow := #curRow + 1 AS current_row, t.id,t.name,t.`date`
FROM `table` AS t
JOIN (SELECT #curRow := 0) r
ORDER BY `date` DESC, id DESC
) t1
WHERE id = 8
);
Try this query:
SELECT MAX(a.id) AS id
FROM mytable a
JOIN (SELECT id,NAME,DATE FROM mytable WHERE id=8) b
ON a.id <> b.id AND a.date < b.date
UNION ALL
SELECT MIN(a.id) AS id
FROM mytable a
JOIN (SELECT id,NAME,DATE FROM mytable WHERE id=8) b
ON a.id > b.id AND a.date >= b.date;
Fiddle here : https://www.db-fiddle.com/f/gTv6Hyeq9opHW83r6Cxfck/4
Or you can use a variable to single define the value:
SET #val = 8;
SELECT MAX(a.id) AS id
FROM mytable a
JOIN (SELECT id,NAME,DATE FROM mytable WHERE id=#val) b
ON a.id <> b.id AND a.date < b.date
UNION ALL
SELECT MIN(a.id) AS id
FROM mytable a
JOIN (SELECT id,NAME,DATE FROM mytable WHERE id=#val) b
ON a.id > b.id AND a.date >= b.date;
if you know date value of record with id=8 you can query next:
SELECT * FROM table
WHERE id <> 8 AND date >= '2020-01-08 20:40:00'
ORDER BY `date` ASC, id ASC
LIMIT 1
and for previous one(inversed):
SELECT * FROM table
WHERE id <> 8 AND date <= '2020-01-08 20:40:00'
ORDER BY `date` DESC, id DESC
LIMIT 1
if you wish to get both with single query, you can use UNION: https://dev.mysql.com/doc/refman/8.0/en/union.html
If you have at least MySQL 8.0 you could use something like this:
SET #row_number = 0;
SET #target = 8;
WITH cte AS (
SELECT (#row_number:=#row_number + 1) AS num,
t.*
FROM (SELECT *
FROM table_name
ORDER BY date DESC) t
)
SELECT *
FROM cte
WHERE num BETWEEN (SELECT num-1 FROM cte WHERE id = #target)
AND (SELECT num+1 FROM cte WHERE id = #target);
The CTE gives you a row number ordered by the date column. The second part of the query pulls everything from teh CTE that has a row number within 1 of the target row you specified (in this case row id 8).
MySQL 8.0+ is required for CTEs. IF you do not have at least MySQL 8.0 you would have to use temp tables for this method.
Previous:
SELECT id, name, date FROM `table` ORDER BY `date` DESC, id DESC LIMIT 1
Next:
SELECT id, name, date FROM `table` ORDER BY `date` ASC, id ASC LIMIT 1
If you need both in a single query:
( SELECT id, name, date FROM `table` ORDER BY `date` DESC, id DESC LIMIT 1 )
UNION ALL
( SELECT id, name, date FROM `table` ORDER BY `date` ASC, id ASC LIMIT 1 )
If you are using 8.0, you can try this:
SELECT LEAD(id) OVER (ORDER BY id DESC) AS 'Next',id,LAG(id) OVER (ORDER BY id DESC) AS 'Previous'
FROM table
WHERE id = 8
ORDER BY `date` DESC, id DESC
I have a stored procedure which queries values from 2 tables (message and message_archived) which contain many data.
CREATE PROCEDURE `get_all_message_report`(IN fromDate TIMESTAMP, IN toDate TIMESTAMP, IN period VARCHAR(15))
BEGIN
DECLARE lfromDate TIMESTAMP;
DECLARE ltoDate TIMESTAMP;
DECLARE lperiod VARCHAR(15);
DECLARE dateFormat VARCHAR(15);
SET lfromDate = fromDate;
SET ltoDate = toDate;
SET lperiod = period;
SET dateFormat = "";
IF lperiod = "monthly"
THEN
SET dateFormat = '%b';
ELSEIF lperiod = "daily"
THEN
SET dateFormat = '%Y-%c-%d';
ELSEIF lperiod = "weekly"
THEN
SET dateFormat = '%x-%v';
END IF;
CREATE TABLE tempMessages(
id bigint(20),
generated_time timestamp,
direction varchar(255),
status varchar(255),
read_status varchar(50),
type varchar(255),
from_number varchar(255),
to_number varchar(255),
INDEX ind (id,generated_time)
);
INSERT INTO tempMessages(id,generated_time,direction,status,read_status,type,from_number,to_number)
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM (
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM message WHERE generated_time BETWEEN lfromDate AND ltoDate
union all
SELECT id,generated_time, direction, status, read_status, type, from_number, to_number
FROM message_archived WHERE generated_time BETWEEN lfromDate AND ltoDate
) t;
SELECT
sentMessageTable.date,
IFNULL(sentMessageTable.sentcount, 0) AS sentMessageCount,
IFNULL(newPassMessagesTable.newpassmessagescount, 0) AS newPassMessagesCount,
IFNULL(newReviewMessagesTable.newreviewmessagescount, 0) AS newReviewMessagesCount,
IFNULL(newFailMessagesTable.newfailmessagescount, 0) AS newFailMessagesCount,
IFNULL(respondedPassThreadsTable.respondedpassthreadcount, 0) AS passThreadsRespondedCount,
IFNULL(respondedReviewThreadsTable.respondedreviewthreadcount, 0) AS reviewThreadsRespondedCount,
IFNULL(respondedFailThreadsTable.respondedfailthreadcount, 0) AS failThreadsRespondedCount
FROM
(
(
/* sent message count*/
SELECT
date,
sum(sentcount1) AS sentcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date,
COUNT(*) AS sentcount1
FROM tempMessages
WHERE direction = 'outgoing' and status in ('SENT','DELIVERED')
GROUP BY date
) t
GROUP BY date
ORDER BY date
) AS sentMessageTable LEFT JOIN
/* new pass messages count */
(
SELECT
date1,
sum(newpassmessagescount1) AS newpassmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date1,
COUNT(*) AS newpassmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='PASS'
GROUP BY date1
) t
GROUP BY date1
ORDER BY date1
)
AS newPassMessagesTable
ON sentMessageTable.date=newPassMessagesTable.date1
LEFT JOIN
/* new review messages count */
(
SELECT
date2,
sum(newreviewmessagescount1) AS newreviewmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date2,
COUNT(*) AS newreviewmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='REVIEW'
GROUP BY date2
) t
GROUP BY date2
ORDER BY date2
)
AS newReviewMessagesTable
ON sentMessageTable.date=newReviewMessagesTable.date2
LEFT JOIN
/* new fail messages count */
(
SELECT
date3,
sum(newfailmessagescount1) AS newfailmessagescount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date3,
COUNT(*) AS newfailmessagescount1
FROM tempMessages
WHERE direction='incoming'
AND read_status='UNREAD' AND type='FAIL'
GROUP BY date3
) t
GROUP BY date3
ORDER BY date3
)
AS newFailMessagesTable
ON sentMessageTable.date=newFailMessagesTable.date3
LEFT JOIN
/* responded pass thread count*/
(
SELECT
date4,
count(*) AS respondedpassthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date4,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date4, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='PASS')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='PASS')
) t
GROUP BY date4
ORDER BY date4
) AS respondedPassThreadsTable
ON sentMessageTable.date = respondedPassThreadsTable.date4
LEFT JOIN
/* responded review thread count*/
(
SELECT
date5,
count(*) AS respondedreviewthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date5,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date5, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='REVIEW')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='REVIEW')
) t
GROUP BY date5
ORDER BY date5
) AS respondedReviewThreadsTable
ON sentMessageTable.date = respondedReviewThreadsTable.date5
LEFT JOIN
/*responded fail thread count*/
(
SELECT
date6,
count(*) AS respondedfailthreadcount
FROM
(
SELECT
DATE_FORMAT(generated_time, dateFormat) AS date6,
from_number,
to_number,
COUNT(*),
MAX(msg.id) AS maxId
FROM tempMessages msg
GROUP BY date6, msg.from_number, msg.to_number
HAVING maxId IN
(
SELECT max(msg.id)
FROM tempMessages msg
WHERE msg.direction = "outgoing"
GROUP BY DATE_FORMAT(generated_time, dateFormat), msg.from_number, msg.to_number
) AND maxId NOT IN (SELECT MIN(msgSub.id)
FROM tempMessages msgSub
GROUP BY msgSub.from_number, msgSub.to_number
HAVING MIN(msgSub.id) = MAX(msgSub.id))
AND from_number IN ( select msg1.to_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='FAIL')
AND to_number IN ( select msg1.from_number
from tempMessages msg1
where msg1.direction = 'incoming' and msg1.type='FAIL')
) t
GROUP BY date6
ORDER BY date6
) AS respondedFailThreadsTable
ON sentMessageTable.date = respondedFailThreadsTable.date6
DROP TABLE tempMessages;
END
Instead of creating a normal table i tried using temporary tables
But i can't join a temp table multiple times in same query.
So i tried using normal table which deletes after execution of the sp
but it is also not helping to reduce the loading time.
while executing the query in sp separately i get result in 10-20 seconds
Any solution to reduce loading time ?
SET #acounts = 0;
SET #bcounts = 0;
SET #cur_year = '2015';
SET #userId = "m00087654";
SELECT *, (#acounts :=#acounts+1) as id FROM (
SELECT distinct userId,cid FROM `TABLE`
WHERE user_id = #userId AND ntype = 'parta' AND date_from <> date_to AND YEAR(ndate) = #cur_year
ORDER BY ndate, cid) AS a;
Time taken 1.22 sec
SELECT *, (#acounts :=#acounts+1) as id FROM (
SELECT distinct userId,cid FROM `TABLE`
WHERE user_id = "m00087654" AND ntype = 'parta' AND date_from <> date_to AND YEAR(ndate) = #cur_year
ORDER BY ndate, cid) AS a;
Time taken 0.0022 sec
when i put user_id = #userId then it take more time comparing user_id = "m00087654"
Any clue why taking more time ?
I have got a problem looks simple, but I could not find the solution.
So, I have got a table with two cols like this:
Time Status
00:00:00.111 Off
00:00:00.222 On
00:00:00.345 On
00:00:01.555 On
00:00:01.666 Off
00:00:02.222 On
00:00:02.422 On
00:00:02.622 Off
00:00:05.888 Off
00:00:05.999 Off
I want to select all statuses of On which lasted for more than 1 second,
in this example, I want the sequence:
00:00:00.222 On
00:00:00.345 On
00:00:01.555 On
Could you guys give me any clue? Many thanks!
A simple GROUP BY and SUM can not do this on your current dataset, so my idea is to add a helper column:
CREATE TABLE someTable(
`time` DATETIME,
status CHAR(3),
helperCol INT
);
The helperCol is an INT and will be set as follows:
CREATE PROCEDURE setHelperCol()
BEGIN
DECLARE finished,v_helperCol INT;
DECLARE status CHAR(3);
DECLARE ts DATETIME;
DECLARE CURSOR st FOR SELECT `time`,status,helperCol FROM someTable WHERE helperCol IS NOT NULL; -- Handy for re-use: No need to go over all data, so you can save the helperCol as permanent value.
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finished = 1;
SELECT #maxVal:=MAX(helperCol) FROM helperCol;
SET finished=0;
SET helperCol=#maxVal;
IF(!helperCol>0) SET helperCol=1;
OPEN st;
FETCH ts,status,v_helperCol FROM st;
WHILE(finished=0) DO
IF(status='Off') v_helperCol=v_helperCol+1;
UPDATE someTable SET helperCol=v_helperCol WHERE `time`=ts; -- Assuming `time` is unique;
FETCH ts,status,v_helperCol FROM st;
END WHILE;
CLOSE st;
END;
Execute the procedure and the result is:
Time Status helperCol
00:00:00.111 Off 2
00:00:00.222 On 2
00:00:00.345 On 2
00:00:01.555 On 2
00:00:01.666 Off 3
00:00:02.222 On 3
00:00:02.422 On 3
00:00:02.622 Off 4
This can now be grouped and processed:
SELECT MAX(`time`)-MIN(`time`) AS diffTime
FROM someTable
WHERE status='ON'
GROUP BY helperCol
HAVING MAX(`time`)-MIN(`time`)>1;
The result of that is (you need to search for the correct datetime functions to apply in the MAX-MIN part):
1.333
Alternative:
You can also process the MAX-MIN in the stored procedure, but that would not be efficiently repeatable as the helperColumn solution is.
SELECT a.time start
, MIN(c.time) end
, TIMEDIFF(MIN(c.time),a.time) duration
FROM
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) a
LEFT
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) b
ON b.status = a.status
AND b.rank = a.rank - 1
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) c
ON c.rank >= a.rank
LEFT
JOIN
( SELECT x.*, COUNT(*) rank FROM my_table x JOIN my_table y ON y.time <= x.time GROUP BY time ) d
ON d.status = c.status
AND d.rank = c.rank + 1
WHERE b.rank IS NULL
AND d.rank IS NULL
AND a.status = 1
GROUP
BY a.time
HAVING duration >= 1;
Another, faster, method might be along these lines - unfortunately I don't think the data types and functions in my version of MySQL support fractions of a second, so this is probably a little bit wrong (there may also be a logical error)...
SELECT time
, status
, cumulative
FROM
( SELECT *
, CASE WHEN #prev = status THEN #i:=#i+duration ELSE #i:=0 END cumulative
, #prev:=status
FROM
( SELECT x.*
, TIME_TO_SEC(MIN(y.time))-TIME_TO_SEC(x.time) duration
FROM my_table x
JOIN my_table y
ON y.time > x.time
GROUP
BY x.time
) n
ORDER
BY time
) a
WHERE cumulative >= 1
AND status = 1;
When trying to check date ranges it does not return values. Here st_date and end_date for usr_id = 1 is sequence so it should return only usr_id = 1 values and should not return usr_id = 3 since it is not sequence . If the date range is not in sequence, it should not return any value.
CREATE TABLE #temp(st_date DATE,end_date DATE,usr_id INT)
INSERT #temp
VALUES ('2007-03-01 ','2015-01-31 ',1),
('2015-02-01 ','2017-04-01 ',1),
('2007-03-01 ','2014-01-31 ',2),
('2007-03-01 ','2015-01-31 ',3),
('2015-03-02 ','2017-04-01 ',3)
DECLARE #st_dt DATE = '2009-02-01 00:00:00',#end_dt DATE = '2017-01-01 00:00:00'
SELECT * FROM #temp WHERE #st_dt BETWEEN st_date AND end_date
AND #end_dt BETWEEN st_date AND end_date
DROP TABLE #temp
SELECT *
FROM #temp t
INNER JOIN #temp t2 ON t.usr_id = t2.usr_id AND t.end_date = DATEADD(dd, -1, t2.st_date)
WHERE #st_dt BETWEEN t.st_date AND t.end_date
AND #end_dt BETWEEN t2.st_date AND t2.end_date