Группировать подмножество результирующего набора по временному интервалу - PullRequest
1 голос
/ 07 июля 2019

У меня есть таблица аудита, в которой записываются определенные действия (например, «доступ», «создание», «обновление» и т. Д.).Я выбираю эти записи, чтобы они могли отображаться в таблице для администратора.

Это прекрасно работает, когда я выбираю все записи для конкретной сущности.Однако, поскольку я использую шаблон Post-Redirect-Get, записи «access» регистрируются при каждом просмотре страницы.В типичном сеансе конечный пользователь может нажать одну и ту же страницу 6 или 7 раз в одном и том же 5-минутном окне.Как следствие, администратор должен прокручивать довольно много избыточных записей доступа, и это понятно отвлекает от пользовательского опыта.

Чтобы решить эту проблему, я написал два запроса.Первый будет искать все записи, которые не являются записями доступа.Второй будет искать записи доступа, а затем группирует их по десятиминутным интервалам.Затем я UNION эти два запроса и упорядочить по дате / времени.

-- Select non 'access' records
SELECT 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(8000)) AS ORIGINAL_VALUE
    ,CAST([CHANGED_VALUE] AS VARCHAR(8000)) AS CHANGED_VALUE
    ,[CREATED_BY]
    ,[CREATED_ON]
FROM [HISTORY] 
WHERE [ORIGIN_ID] = 500 AND [ORIGIN_ID_TYPE] = 4 AND [ACTION_TYPE_ID] != 1

UNION

-- Select 'access' records and group them into 10 minute intervals by ts
SELECT 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(255)) AS ORIGINAL_VALUE
    ,CAST([CHANGED_VALUE] AS VARCHAR(255)) AS CHANGED_VALUE
    ,[CREATED_BY]
    ,DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0) AS CREATED_ON
FROM [HISTORY]
WHERE [ACTION_TYPE_ID] = 1 AND [ORIGIN_ID] = 500 AND [ORIGIN_ID_TYPE] = 4
GROUP BY 
     [ORIGIN_ID]
    ,[ORIGIN_ID_TYPE]
    ,[REFERENCE_ID]
    ,[REFERENCE_ID_TYPE]
    ,[ACTION_TYPE_ID]
    ,CAST([ORIGINAL_VALUE] AS VARCHAR(255))
    ,CAST([CHANGED_VALUE] AS VARCHAR(255))
    ,[CREATED_BY]
    ,DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0)

ORDER BY [CREATED_ON] DESC

SQLFiddle (у меня было ограниченное количество данных, которые SQLFiddle позволил бы мне загружать)

Я чувствую, что может быть лучший способ сделать это, который не требует, чтобы я использовал UNION.Для того, чтобы сделать это таким образом, я должен был привести свои столбцы TEXT к столбцам VARCHAR, и я чувствую, что может быть лучшая альтернатива.Любые предложения относительно того, как этот запрос может быть улучшен?

1 Ответ

0 голосов
/ 07 июля 2019

Устраните союз, используя эти две группировки. Второе также становится новым выражением для объединенного столбца created_on. Первый также может быть использован для управления сортировкой, а затем отброшен. (Не забудьте также удалить фильтр на action_type_id.):

case when action_type_id <> 1 then 1 else 2 end, 
case when action_type_id <> 1
    then created_on
    else DATEADD(MINUTE, DATEDIFF(MINUTE, 0, [CREATED_ON]) / 10 * 10, 0)
end

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

Обратите внимание, что это не совсем работает, как если бы можно было записать две такие строки с одинаковой отметкой времени. Вам нужно сгруппироваться по другому идентификатору (или просто row_number()), чтобы обойти это, но я подозреваю, что это будет ненужным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...