Reputation: 3
I need an SQL query that checks for whether a person is active for two consecutive weeks in the year.
For example,
Table1:
Name | Activity | Date
Name1|Basketball| 08-08-2014
Name2|Volleyball| 08-09-2014
Name3|None | 08-10-2014
Name1|Tennis | 08-14-2014
I want to retrieve Name1 because that person has been active for two consecutive weeks in the year.
This is my query so far:
SELECT DISTINCT Name
FROM Table1
Where YEAR(Date) = 2014 AND
Activity NOT 'None' AND
This is where I would need the logic that checked for an activity in two consecutive weeks. A week can be described as 7 to 14 days later. I am working with MYSQL.
Upvotes: 0
Views: 145
Reputation: 75
From the top of my head, I suggest this query:
SELECT DISTINCT t1.Name
FROM Table1 AS t1, Table1 AS t2
WHERE t1.Name = t2.Name
AND t2.Date BETWEEN t1.Date-7 AND t1.Date+7;
The idea is basically: you call your table twice, select the rows whose names match, and then keep only those whose second date are up to 7 days away from the first date.
Upvotes: 0
Reputation: 883
I don't know if it is performance relevant, but I like concise queries:
SELECT t1.Name
FROM Table1 t1, Table1 t2
Where t1.Name=t2.Name AND
t1.Date >= '2014-01-01' AND t1.Date < '2015-01-01' AND
t1.Activity <> 'None' AND
t1.Date < t2.Date AND
datediff(t2.Date, t1.Date) <= 14
I liked the hint of @user2067753 about the YEAR(date)
.
I used the sqlfiddle of the answer above to check the performance using the explain
syntax. It seems that avoiding sub queries as in VACN's answer or mine is beneficial (see join vs sub query)
Upvotes: 1
Reputation: 35563
I have avoided using YEAR(Date
) in the where clause deliberately, and recommend you do too. Using functions on multiple rows of data to suit a single criteria (2014) never makes sense to me, plus it destroys the effectiveness of indexes (see "sargable" at wikipedia). Way easier to just define a filter by a date range IMHO.
I've used a correlated subquery to derive nxt_date
which might not scale very well, but overall the performance will depend on your indexes most probably.
select distinct
name
from (
select
t.name
, t.Activity
, t.`Date`
, (
select min(table1.`Date`) from table1
where t.name = table1.name
and table1.Activity <> 'None'
and table1.`Date` > t.`Date`
) as nxt_date
from table1 as t
where ( t.`Date` >= '2014-01-01' and t.`Date` < '2015-01-01' )
and t.Activity <> 'None'
) as sq
where datediff(sq.nxt_date, sq.`Date`) <= 14
;
see: http://sqlfiddle.com/#!9/cbbb3/9
Upvotes: 2
Reputation: 1269553
You can do the logic using an exists
subquery:
select t.*
from table1 t
where exists (select 1
from table1 t2
where t2.name = t.name and
t2.date between t.date + 7 and t.date + 14
);
Upvotes: 1