View grouped records in a date or time sequence. P

2019-09-04 17:07发布

问题:

Say you had a table in your SQL Server (EDIT: prensently SQL Server 2008) database that look like this:

Date                    Id State
=================================
2013-09-12 15:02:41,844 1 OK
2013-09-12 15:02:41,844 2 OK
2013-09-12 15:02:41,844 3 ERROR
2013-09-12 15:02:41,844 4 ERROR
2013-09-12 15:02:41,844 5 ERROR
2013-09-13 15:02:41,844 1 ERROR
2013-09-14 15:02:41,844 1 OK
2013-09-15 15:02:41,844 1 ERROR
2013-09-15 15:02:41,844 2 ERROR

The purpouse of the table is to save records state. I wrote this table but now i cannot figure out how to query it for an overview of the different states during a time sequence.

The result i am looking for is this:

2013-09-12 16:00:00 OK 2
2013-09-12 16:00:00 ERROR 3
2013-09-13 16:00:00 OK 1
2013-09-13 16:00:00 ERROR 4
2013-09-14 16:00:00 OK 2
2013-09-14 16:00:00 ERROR 3
2013-09-15 16:00:00 OK 0
2013-09-15 16:00:00 ERROR 5

EDIT: What i am trying to achieve is a day-by-day view of the state of my objects. which objects has an error and which ones are ok. Maybe a garage would be a better example, but i will stick to this.

  • On the 12th 3 objects had ERROR and 2 where OK.
  • On the 13th one object went from OK to Error. I now have 4 objects in a ERROR state and one that is OK.
  • On the 14th my object with id 1 is fixed and i am now back to two objects that are OK >and three that has an ERROR state

I have figured out (found) how to generate a sequence of dates (without using variable declarations) like this:

;WITH dates
AS (
    SELECT CAST('2013-12-17 16:00:00' AS DATETIME) 'date'

    UNION ALL

    SELECT DATEADD(dd, 1, t.DATE)
    FROM dates t
    WHERE DATEADD(dd, 1, t.DATE) <= GETDATE()
    )
SELECT dates.DATE   
FROM dates

And i have a query that does the relevant grouping (i think) that delivers a desired output (and point):

Date State Count(state)
=======================    
2013-09-12 16:00:00 OK 2
        2013-09-12 16:00:00 ERROR 3
        2013-09-13 16:00:00 ERROR 1
        2013-09-14 16:00:00 OK 1
        2013-09-15 16:00:00 ERROR 1

So the question is, how do you marry the sequence of dates to my grouping result to achieve the desired result.

回答1:

With SQL Server 2012 providing window functions you can use the following query:

SELECT date,
       sum(ok_mod) over (order by date) as ok
FROM (
  SELECT date,
         sum(case when state = 'OK' then 1
                  when state = 'ERROR' and prev_state is not null then -1
                  else 0
             end) as ok_mod
  FROM (
    SELECT date, id, state,
           lag(state) over (partition by id order by date) prev_state
    FROM data
  ) AS data
  GROUP BY date
) AS data
ORDER BY date;

This gives you only OK part, but you can easily union corresponding query for ERROR part also. SQL Fiddle here.

With 2008 version imho you won't make it without a procedure or really complex query.