SQL: как получить последние элементы? - PullRequest
1 голос
/ 18 апреля 2011

У меня есть журнал для документов, которые проходят через мое приложение.Журнал выглядит следующим образом:

TABLE: log
==================================================
| log_id | document_id | status_code | timestamp |
==================================================
| 1      | 10          | 100         | 12345     |
--------------------------------------------------
| 2      | 10          | 200         | 23456     |
--------------------------------------------------

Мне нужен список document_id, который "застрял" в определенном status_code на заданную продолжительность (скажем, 10 минут; timestamp - метка времени UnixКстати).Если определенный document_id «застрял» в определенном status_code, то status_code будет последним status_code для этого document_id.

Как я могу запросить это?В двух вещах, в которых я не уверен:

  1. Как проверить, был ли документ в определенном состоянии в течение определенного периода времени?Я предполагаю, что я могу использовать какую-то функцию / формулу в моем SQL (например, now - 10 минут), но я не знаю, как это сделать.
  2. Как проверить продолжительностьтолько последний код состояния?

Ответы [ 3 ]

2 голосов
/ 18 апреля 2011
SELECT log.document_id
     , (UNIX_TIMESTAMP() - log.timestamp) / 60
       AS MinutesSinceLastChange 
FROM log
  JOIN
    ( SELECT document_id
           , MAX(timestamp) AS last_change
      FROM log
      GROUP BY document_id
      HAVING (last_change < (UNIX_TIMESTAMP() - 60 * 10))  <-- that is 10 minutes
    ) AS grp
    ON  grp.document_id = log.document_id
    AND grp.last_change = log.timestamp
WHERE log.status_code = "200"             <-- code you want to check
0 голосов
/ 18 апреля 2011
SELECT log.document_id, log.status_code, max(log.timestamp) - min(log.timestamp)
FROM ( 
  SELECT MAX(log_id) as log_id
  FROM log
  GROUP BY document_id) latestLog
    INNER JOIN log latestStatus ON latestStatus.log_id = latestLog.log_id
    INNER JOIN log on latestStatus.status_code = log.status_code
GROUP BY log.document_id, log.status_code
HAVING (max(log.timestamp) - min(log.timestamp)) > 600
0 голосов
/ 18 апреля 2011

для твоего нет.один и нет.два вопроса, это мое предложение для (я полагаю, вы используете MySQL):

SELECT 
    `document_id`, 
    SUBSTR(GROUP_CONCAT(RPAD(`status_code`,5) ORDER BY `timestamp` DESC), 1, 5) AS `last_status`,
    SUBSTR(GROUP_CONCAT(RPAD(`status_code`,5) ORDER BY `timestamp` DESC), 7, 5) AS `prev_status`,

    UNIX_TIMESTAMP(SUBSTR(GROUP_CONCAT(FROM_UNIXTIME(`timestamp`) ORDER BY `timestamp` DESC), 1, 19)) AS `last_timestamp`,
    UNIX_TIMESTAMP(SUBSTR(GROUP_CONCAT(FROM_UNIXTIME(`timestamp`) ORDER BY `timestamp` DESC), 21, 19)) AS `prev_timestamp`
FROM `log`
GROUP BY `document_id`
HAVING `last_timestamp` - `prev_timestamp` > 60*10 AND `last_status` IN (100,200);

Хорошо, что там происходит.Мы группируем строки по document_id и упорядочиваем коды состояния и временные метки внутри GROUP_CONCAT для получения последней и предварительной записи.

Если ваш код состояния может содержать более 5 цифр, то замените его RPAD (status_code, X), где X - максимальное число кодов длины status_

60 * 10 - это 10 минут

last_status IN (100,200) - коды состояния, которые вы хотите получить только.

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