Oracle GROUP BY похожие временные метки? - PullRequest
6 голосов
/ 02 апреля 2012

У меня есть таблица активности со структурой, подобной этой:

id  prd_id  act_dt               grp
------------------------------------
1   1       2000-01-01 00:00:00
2   1       2000-01-01 00:00:01
3   1       2000-01-01 00:00:02
4   2       2000-01-01 00:00:00
5   2       2000-01-01 00:00:01
6   2       2000-01-01 01:00:00
7   2       2000-01-01 01:00:01
8   3       2000-01-01 00:00:00
9   3       2000-01-01 00:00:01
10  3       2000-01-01 02:00:00

Я хочу разделить данные в этой таблице активности по продукту (prd_id) и дате активности (act_dt) и обновить столбец группы (grp) значением последовательности для каждого из этих группы.

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

Для данных примера группы будут:

id  prd_id  act_dt               grp
------------------------------------
1   1       2000-01-01 00:00:00  1
2   1       2000-01-01 00:00:01  1
3   1       2000-01-01 00:00:02  1
4   2       2000-01-01 00:00:00  2
5   2       2000-01-01 00:00:01  2
6   2       2000-01-01 01:00:00  3
7   2       2000-01-01 01:00:01  3
8   3       2000-01-01 00:00:00  4
9   3       2000-01-01 00:00:01  4
10  3       2000-01-01 02:00:00  5

Какой метод я бы использовал для достижения этой цели?

Размер таблицы составляет ~ 20 миллионов строк, если это влияет на метод, используемый для решения проблемы.

1 Ответ

2 голосов
/ 02 апреля 2012

Я не специалист по Oracle, поэтому я предпочитаю лучший вариант для одной строки:

    (CAST('2010-01-01' AS DATETIME) - act_dt) * 24 * 60 * 60      AS time_id,

Это просто должно быть «количество секунд от [aDateConstant] до act_dt». Результат может быть отрицательным. Это просто должно быть количество секунд, чтобы превратить ваш act_dt в INT. Остальное должно работать нормально.

WITH
  sequenced_data
AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY prd_id  ORDER BY act_dt)      AS sequence_id,
    (CAST('2010-01-01' AS DATETIME) - act_dt) * 24 * 60 * 60      AS time_id,
    *
  FROM
    yourTable
)
SELECT
  DENSE_RANK() OVER (PARTITION BY prd_id ORDER BY time_id - sequence_id) AS group_id,
  *
FROM
  sequenced_data 

Пример данных:

 sequence_id | time_id | t-s | group_id
-------------+---------+-----+----------
      1      |   1     |  0  |    1
      2      |   2     |  0  |    1
      3      |   3     |  0  |    1
      4      |   8     |  4  |    2
      5      |   9     |  4  |    2
      6      |   12    |  6  |    3
      7      |   14    |  7  |    4
      8      |   15    |  7  |    4

1011 *
*

ПРИМЕЧАНИЕ: Это означает , что не нескольких записей с одним и тем же временем. Если они есть, их сначала нужно отфильтровать. Возможно просто использование GROUP BY в предыдущем CTE.

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