Get rows without an 'end' event
Here's a few ways.


Use NOT EXISTS for an anti semi join



SELECT Id,
       Event,
       Thing
FROM   dbo.TimeSeries t1
WHERE  NOT EXISTS(SELECT *
                  FROM   dbo.TimeSeries t2
                  WHERE  t1.Thing = t2.Thing
                         AND t2.Event = 'E');




Partition by Thing and find the minimum (alphabetically first) event in each partition. If it is S rather than E this Thing has no end event.



WITH T
     AS (SELECT *,
                MIN(Event) OVER (PARTITION BY Thing) AS Evt
         FROM   dbo.TimeSeries
         WHERE  Event IN ( 'E', 'S' ))
SELECT Id,
       Event,
       Thing
FROM   T
WHERE  Evt = 'S';




Partition by Thing and use LAG to look at the preceding row to the current row when ordering by event alphabetically.  If the current row is S and there is no preceding row Evt will be NULL. Just preserve any such rows. This is 2012+ syntax.



WITH T
     AS (SELECT *,
                LAG(Event) OVER (PARTITION BY Thing ORDER BY Event) AS Evt
         FROM   dbo.TimeSeries
         WHERE  Event IN ( 'E', 'S' ))
SELECT Id,
       Event,
       Thing
FROM   T
WHERE  Event = 'S' AND Evt IS NULL;