Reputation: 3276
I've got a table that looks like this
WeekId PassesCondition
----------------------------------
1 1
2 0
3 0
4 1
5 1
6 1
I need to write a query that counts the consecutive weeks back from the max WeekId
that the condition has been passed.
I've done some searching and I seem to need to do something with a CTE
and ROW_NUMBER()
possibly. I've tried a few things, but the results haven't even been worthy to post as a "What I've tried so far".
The output should be just a count of how many weeks from the Max(WeekId)
was the condition passed. e.g. 1, 2, 5, etc.
Upvotes: 0
Views: 933
Reputation: 15185
If you need to account for the multiple start and stops you can count the islands using a query similar to:
DECLARE @T TABLE(WeekId INT, PassedCondition BIT)
INSERT @T VALUES (1,1),(2,0),(3,0),(4,1),(5,1),(6,1),(7,1),(8,0),(9,0),(10,1)
;WITH Holes AS(SELECT WeekID FROM @T WHERE PassedCondition=0),
SegmentStart AS
(
SELECT WeekId, HoleWeekId
FROM
(
SELECT This.WeekId, HoleWeekId = MIN(H.WeekId)
FROM @T This
INNER JOIN Holes H ON H.WeekId > This.WeekID AND PassedCondition=1
GROUP BY This.WeekId
UNION
SELECT WeekId = MAX(WeekID), HoleWeekId=MAX(WeekID)+1
FROM @T
WHERE PassedCondition=1
)AS X
)
SELECT
WeekSegmentEnd = HoleWeekId-1,
ConsecutiveCount = COUNT(*)
FROM
SegmentStart
GROUP BY
HoleWeekId
Upvotes: 1
Reputation: 164164
Count the rows that are between the maximum weekid
that has passesCondition = 0
(exclusive) and the maximum weekid
(exclusive):
SELECT COUNT(*)
FROM tablename t
WHERE
(t.weekid < (SELECT MAX(weekid) FROM tablename))
AND
(t.weekid > (SELECT MAX(weekid) FROM tablename WHERE passesCondition = 0));
If you want to include the last weekid
you change <
to <=
.
Upvotes: 0
Reputation: 1270593
Assuming the condition is only 0
or 1
:
select count(*)
from t
where t.weekid > (select max(t2.weekid) from t t2 where t2.passesCondition = 0) or
not exists (select 1 from t t2 where t2.passesCondition = 0);
The second condition is unnecessary if you know a row with passesCondition = 0
exists.
If you like using window functions, you can also do this with a cumulative reverse min:
select count(*)
from (select t.*,
min(passesCondition) over (order by weekid desc) as running_min
from t
) t
where running_min = 1;
Or, not exists
can be used:
select count(*)
from t
where not exists (select 1
from t t2
where t2.weekid > t.weekid and t2.passesCondition = 0
);
Or > all
:
select count(*)
from t
where t.weekid > all (select t2.weekid from t t2 where t2.passesCondition = 0);
I hadn't realized there are so many different way to express this. No doubt, there are quite a few more.
Upvotes: 3