обновить столбец во времени - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть следующая таблица:

    id  Prod_id Year    Quartar Start_flag  End_flag    status
1   A001    2015    1   0   0   0
2   A001    2015    2   1   0   0
3   A001    2015    3   0   0   0
4   A001    2015    4   0   0   0
5   A001    2016    1   0   0   0
6   A001    2016    2   0   0   0
7   A001    2016    3   0   1   0
8   A001    2016    4   0   0   0
9   B002    2015    1   0   0   0
10  B002    2015    2   0   0   0
11  B002    2015    3   0   0   0
12  B002    2015    4   1   0   0
13  B002    2016    1   0   1   0
14  B002    2016    2   0   0   0
15  B002    2016    3   0   0   0
16  B002    2016    4   0   0   0
17  c003    2015    1   0   1   0
18  c003    2015    2   0   0   0
19  c003    2015    3   0   1   0
20  c003    2015    4   1   0   0
21  c003    2016    1   0   0   0
22  c003    2016    2   0   0   0
23  c003    2016    3   0   0   0
24  c003    2016    4   0   0   0

Таблица имеет уникальный индекс с использованием (Prod_id, Year, Quarter) и кластеризованный индекс (Prod_id, Year, Quarter).другими словами, таблица упорядочена по Моей таблице:

  • Более 20 миллионов уникальных строк на основе (Prod_id, Year, Quarter)
  • У каждого продукта может быть start_flagи не может.
  • В случае, если у продукта есть начальный флаг, он может иметь конечный флаг до и после начального флага и может иметь конечный флаг только перед начальным флагом.
  • Каждый продукт запускается с 2010 по 2018 год с 4 кварталамикаждый год.

Я хочу обновить столбец состояния = 1 во времени от start_flag до одной четверти до первого end_flag после start_flag.Если флаг завершения отсутствует, обновление будет выполняться до последних записей для выбранного продукта.

После внедрения обновления обновленная таблица должна выглядеть следующим образом:

 id Prod_id Year    Quartar Start_flag  End_flag    status
1   A001    2015    1   0   0   0
2   A001    2015    2   1   0   1
3   A001    2015    3   0   0   1
4   A001    2015    4   0   0   1
5   A001    2016    1   0   0   1
6   A001    2016    2   0   0   1
7   A001    2016    3   0   1   0
8   A001    2016    4   0   0   0
9   B002    2015    1   0   0   0
10  B002    2015    2   0   0   0
11  B002    2015    3   0   0   0
12  B002    2015    4   1   0   1
13  B002    2016    1   0   1   0
14  B002    2016    2   0   0   0
15  B002    2016    3   0   0   0
16  B002    2016    4   0   0   0
17  c003    2015    1   0   1   0
18  c003    2015    2   0   0   0
19  c003    2015    3   0   1   0
20  c003    2015    4   1   0   1
21  c003    2016    1   0   0   1
22  c003    2016    2   0   0   1
23  c003    2016    3   0   0   1
24  c003    2016    4   0   0   1

I Уже имплантированорешение с использованием pl / pgsql с использованием курсора. Но решение с использованием курсора занимает более 30 часов, чтобы обновить этот столбец в моем случае.Есть ли альтернативный способ сделать это обновление без использования курсора?Я использую PostgreSQL 10.6.Пожалуйста, совет и спасибо.

1 Ответ

0 голосов
/ 13 декабря 2018

Отказ от ответственности : Я не совсем понял ваш вариант использования с кварталами и то, как диапазоны start_flag должны работать с течением времени.Таким образом, следующее решение не смотрит на временную часть.Если бы вы немного объяснили свой пример времени, я уверен, что следующему решению нужна лишь небольшая настройка (например, предложение PARTITION) для получения работы за вас.


demo:db <> fiddle

Мои образцы данных:

id   start_flag   end_flag
1    0            0
2    1            0
3    0            0
4    0            0
5    0            1
6    0            0
7    1            0
8    0            1
9    0            0
10   0            1
11   0            0
12   0            1
13   1            0
14   0            0
16   0            0

Запрос:

SELECT
    *,
    GREATEST(
         first_value(start_flag - end_flag) OVER (PARTITION BY sum ORDER BY id), 
         0
    ) as status
FROM (
    SELECT 
        *,
        SUM(start_flag + end_flag) OVER (ORDER BY id)
    FROM mytable
) s

Результат:

id   start_flag   end_flag   status
1    0            0          0
2    1            0          1
3    0            0          1
4    0            0          1
5    0            1          0
6    0            0          0
7    1            0          1
8    0            1          0
9    0            0          0
10   0            1          0
11   0            0          0
12   0            1          0
13   1            0          1
14   0            0          1
16   0            0          1

Объяснение:

Использование оконных функций :

  1. Совокупный SUM каждого потенциального "изменения состояния" (start_flag или end_flag).Это создает группы.В каждой группе одинаковый статус.(см. столбец SUM в скрипте)
  2. first_value оконная функция: для каждой группы проверять, было ли изменение статуса выполнено с помощью start_flag (положительно) или end_flag (отрицательно)
  3. GREATEST() нормализует отрицательные значения до нуля.

Редактировать: Добавление prod_id и year/quarters

В целом весь сценарий использования очень похож- только с использованием оконных функций:

демо: db <> fiddle

  1. Вместо того, чтобы заказывать по id, я заказываю по year, quarter
  2. Вместо просмотра всего набора данных я использую разделение (над prod_id) для оконных функций:

Расширенный запрос:

SELECT
    *, 
    GREATEST(
         first_value(start_flag - end_flag) OVER (PARTITION BY prod_id, sum ORDER BY year, quarter), 
         0
    ) as status
FROM (
    SELECT 
        *,
        SUM(start_flag + end_flag) OVER (PARTITION BY prod_id ORDER BY year, quarter)
    FROM mytable
) s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...