Добавить несколько «изменений во времени» из одной таблицы - PullRequest
0 голосов
/ 21 июля 2011

Моя таблица принимает временную метку всякий раз, когда изменяется статус пользователя. Каждый день он начинается в «а» и всегда прогрессирует a-> b-> c-> d-> e -> ...

Итак, я пытаюсь найти общее время между «a» и «b» плюс время между «c» и «d» плюс «e» и «f» и так далее.

Это работает, чтобы получить время между двумя состояниями:

SELECT cast(us2.status_timestamp as date) - cast(us1.status_timestamp as date)
FROM user_status US1, user_status US2
WHERE US1.statID = 'a' and us2.statID = 'b'
AND US1.user_ID = US2.user_ID
AND US1.work_date = US2.work_date

Есть ли способ сделать это, не выполняя этот оператор выбора несколько раз, а затем добавляя результаты? Я чувствую, что есть более быстрый путь.

Примечание: использование жабы для Oracle

Ответы [ 3 ]

1 голос
/ 21 июля 2011

Если я правильно понимаю ваши требования, будет работать следующий запрос:

SELECT SUM (CAST (us2.status_timestamp AS date) - CAST (us1.status_timestamp AS date))
FROM   user_status us1, user_status us2
WHERE  CHR (ASCII (us1.statid) + 1) = us2.statid
   AND MOD (ASCII (us1.statid), 2) <> 0
   AND us1.user_id = us2.user_id
   AND us1.work_date = us2.work_date;

MOD (ASCII (us1.statid), 2) вернет 0 для символов с четным значением ASCII и что-то еще для всех других значений. 'a' равно 97, поэтому мы всегда хотим начинать с того, что это значение не равно 0. Мы можем использовать очень похожую логику, чтобы получить следующее значение в последовательности: преобразовать букву в ее значение ASCII, добавить 1, а затем преобразовать обратно. Использование этого значения в соединении позволяет нам найти соответствующий конец для каждого нашего времени начала. Наконец, мы просто суммируем все различия.

1 голос
/ 21 июля 2011

Вероятно, вы можете использовать аналитические функции LEAD и LAG

SELECT cast(status_timestamp as date) - cast(prior_status_timestamp as date) diff,
       user_id,
       work_date,
       statID
  FROM (
    SELECT status_timestamp,
           lag(status_timestamp) over 
              (partition by user_id, 
                            work_date 
               order by status_timestamp) prior_status_timestamp,
           user_id,
           statID,
           work_date
      FROM user_status )
 WHERE statID in ('b','d','f')      

Для каждой строки в таблице будет получена временная метка статуса предыдущей строки для того же user_id и work_date (так что'row для каждого пользователя в каждый день будет иметь значение prior_status_timestamp, равное NULL).Затем отображается разница между текущей строкой и предыдущей строкой.Затем вы можете агрегировать соответствующим образом.

0 голосов
/ 21 июля 2011
SELECT US1.user_ID, SUM(difference)
FROM (
SELECT US1.user_ID, cast(us2.status_timestamp as date) - cast(us1.status_timestamp as date) AS difference
FROM user_status US1, user_status US2
WHERE 
   ((US1.statID = 'a' and us2.statID = 'b') OR
    (US1.statID = 'C' AND us2.statID = 'D') OR
    (US1.statID = 'E' AND us2.statID = 'F'))
AND US1.user_ID = US2.user_ID
AND US1.work_date = US2.work_date
) GROUP BY US1.user_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...