Назад | Перейти на главную страницу

создать представление для отображения статуса резервного копирования каждые 10 минут

У меня есть вопрос,

в моей таблице есть следующие данные:

userID, startTime, EndTime
—————————————
101, 04/11/2013 11:00:00, 04/11/2013 11:55:00
102, 04/11/2013 11:00:00, 04/11/2013 11:24:00
103, 04/11/2013 11:20:00, 04/11/2013 11:45:00
104, 04/11/2013 11:30:00, 04/11/2013 11:35:00
105, 04/11/2013 11:40:00, 04/11/2013 11:55:00

Могу ли я использовать представление для отображения состояния резервного копирования каждые 10 минут?

Интересно, что получилось так:

time, count
——————————
04/11/2013 11:00:00, 2
04/11/2013 11:10:00, 2
04/11/2013 11:20:00, 3
04/11/2013 11:30:00, 3
04/11/2013 11:40:00, 3
04/11/2013 11:50:00, 2
04/11/2013 12:00:00, 0



04/11/2013 11:00:00 – 04/11/2013 11:09:59 have 2 jobs, 101 & 102
04/11/2013 11:10:00 – 04/11/2013 11:19:59 have 2 jobs, 101 & 102
04/11/2013 11:20:00 – 04/11/2013 11:29:59 have 3 jobs, 101 & 102 & 103
…
04/11/2013 11:50:00 – 04/11/2013 11:59:59 have 2 jobs, 101 & 105
04/11/2013 12:00:00 – 04/11/2013 12:09:59 have 0 job

Интересно, можете ли вы мне помочь ... Большое спасибо

На самом деле не место для решений на основе кода (см. Переполнение стека), но я укушу:

Во-первых, я предполагаю, что есть таблица с именами логинов со следующими данными ...

IF OBJECT_ID('tempdb..logins') IS NOT NULL DROP TABLE logins;
GO
CREATE TABLE logins (userID INT, startTime DATETIME, endTime DATETIME)
GO
INSERT INTO logins (userID, startTime, endTime)
VALUES (101, '2013-11-04T11:00:00', '2013-11-04T11:00:00')
      ,(102, '2013-11-04T11:00:00', '2013-11-04T11:24:00')
      ,(103, '2013-11-04T11:20:00', '2013-11-04T11:45:00')
      ,(104, '2013-11-04T11:30:00', '2013-11-04T11:35:00')
      ,(105, '2013-11-04T11:40:00', '2013-11-04T11:55:00');

GO

Если вы просто хотите знать, на какой 10-минутный период приходится вход в систему, неплохим простым (хотя и несколько волшебным) способом было бы использовать нулевую дату ...

SELECT
    period_start = DATEADD(MINUTE, DATEDIFF(MINUTE, 0, l.startTime) / 10 * 10, 0),
    l.*
FROM logins l
GO

... так что для простого подсчета на основе периода ...

WITH starts AS (
    SELECT
        period_start = DATEADD(MINUTE, DATEDIFF(MINUTE, 0, l.startTime) / 10 * 10, 0),
        l.*
    FROM logins l
)
SELECT
    period_start,
    login_count = COUNT(1)
FROM starts
GROUP BY period_start
GO

Однако, если вы хотите также показать пробелы с нулевым счетчиком, вам понадобится функция, чтобы получить все даты, а затем присоединиться к ней слева ...

-- periods: a table-function to get a series of date/times intervals between two dates
-- (tally approach taken from Itzik Ben-Gan's article http://sqlmag.com/sql-server/virtual-auxiliary-table-numbers)
IF OBJECT_ID('tempdb..periods') IS NOT NULL DROP FUNCTION periods;
GO
CREATE FUNCTION periods(
    @start_date DATETIME2,
    @end_date    DATETIME2 = GETDATE,
    @incr_mins    INT = 10
)
RETURNS TABLE
AS RETURN (
    WITH 
        E1(N) AS (
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
            SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
        ),                                      -- 10^1     or 10 rows
        E2(N) AS (SELECT 1 FROM E1 a, E1 b),    -- 10^2     or 100 rows
        E4(N) AS (SELECT 1 FROM E2 a, E2 b),    -- 10^4     or 10,000 rows
        E8(N) AS (SELECT 1 FROM E4 a, E4 b),    -- 10^8     or 100,000,000 rows
        E16(N) AS (SELECT 1 FROM E8 a, E8 b),   -- 10^16 or 10,000,000,000,000,000 rows
        E32(N) AS (SELECT 1 FROM E16 a, E16 b), -- 10^32 or 100,000,000,000,000,000,000,000,000,000,000 rows
        E64(N) AS (SELECT 1 FROM E32 a, E32 b), -- 10^64 or 10,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000 rows

        starts AS (
            SELECT TOP (CEILING(ABS(DATEDIFF(MINUTE, @start_date, @end_date)) / @incr_mins))
                period_start = DATEADD(MINUTE, 
                                       @incr_mins * (ROW_NUMBER() OVER (ORDER BY (SELECT 1)) - 1), 
                                       @start_date)
            FROM E64
        ),
        ends AS (
            SELECT
                period_start,
                period_end = DATEADD(MINUTE, @incr_mins, period_start)
            FROM starts
        )
    SELECT period_start, period_end
    FROM ends
)
GO

Теперь вы можете использовать эту функцию для подсчета логинов по периодам ...

SELECT
    p.period_start,
    login_count = SUM(CASE WHEN l.userID IS NULL THEN 0 ELSE 1 END)
FROM periods('2013-11-04T00:00:00', '2013-11-05T00:00:00', 10) p
LEFT JOIN logins l ON 
    l.startTime >= p.period_start AND 
    l.startTime < p.period_end
GROUP BY p.period_start
GO

Обратите внимание, что вызов функции немного дороже, поэтому было бы лучше заполнить хорошо проиндексированную «календарную» таблицу, которая предварительно рассчитывает все ваши периоды, и вместо этого присоединиться к ней.

Надеюсь это поможет.

J