Есть ли способ динамически обновлять / увеличивать значения столбцов при добавлении нового значения? - PullRequest
2 голосов
/ 02 августа 2020

Приносим извинения, если заголовок не передает вопрос должным образом.

Если у меня есть таблица Postgres с именем Person со следующими столбцами и данными:

name | age | order |
John | 42  | 1     |
Sam  | 27  | 2     |
Phil | 19  | 3     |

Столбец заказа - это Float, который определяет порядок, в котором клиент должен отображать список лиц.

Есть ли оптимальный эффективный способ вставить Person с существующим порядком, но делегируя БД для автоматического увеличения значений в столбце порядка ? Если да, то как?

Например, если я добавляю нового человека (Emma, 56, 2), я хочу, чтобы результат был

name | age | order |
John | 42  | 1     |
Sam  | 27  | 3     |
Phil | 19  | 4     |
Emma | 56  | 2     |

Примечание. Теперь заказы Сэма и Фила увеличиваются.

Возможное решение: Я могу воспользоваться функцией float и получить среднее значение предыдущего и текущего ордера. Таким образом, в приведенном выше примере это будет 1 (для Джона) + 2 (для Эммы во вставке) / 2. Новый порядок для Эммы будет равен 1,5, что хорошо подходит, как показано ниже:

name | age | order |
John | 42  | 1     |
Sam  | 27  | 2     |
Phil | 19  | 3     |
Emma | 56  | 1.5   |

Но для этого требуется несколько вызовов БД, отсюда и вопрос.

Изменить: хотя я пошел с ответом Джорджа Джозефа в окончательной реализации, правильным ответом, который фактически ответил на вопрос, был зажим. Поэтому я пометил его ответ как принятый.

Ответы [ 3 ]

2 голосов
/ 02 августа 2020

Если вы хотите обновить существующие записи, вот как:

Сначала проверьте, не конфликтует ли новое значение с существующим. Если да, увеличьте существующие значения на 1 (это все равно будет работать с целыми числами).

Я использую sort_order вместо order, потому что последнее зарезервировано в SQL.

CREATE FUNCTION person_check_sort_order() RETURNS TRIGGER AS 
$def$
BEGIN
PERFORM * FROM person WHERE sort_order = new.sort_order;
IF FOUND THEN
UPDATE person SET sort_order = sort_order + 1 WHERE sort_order >= new.sort_order;
END IF;
RETURN new;
END;
$def$
LANGUAGE plpgsql;

CREATE TRIGGER person_insert_trg BEFORE INSERT ON person
FOR EACH ROW EXECUTE PROCEDURE person_check_sort_order();

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

CREATE OR REPLACE FUNCTION person_check_sort_order() RETURNS TRIGGER AS 
$def$
BEGIN
PERFORM * FROM person WHERE sort_order = new.sort_order;
IF FOUND THEN
UPDATE person SET sort_order = sort_order + 1 WHERE sort_order = new.sort_order;
END IF;
RETURN new;
END;
$def$
LANGUAGE plpgsql;
--DROP TRIGGER person_insert_trg ON person;
CREATE TRIGGER person_insert_trg BEFORE INSERT OR UPDATE OF sort_order ON person
FOR EACH ROW EXECUTE PROCEDURE person_check_sort_order();
1 голос
/ 02 августа 2020

Вот как вы можете работать над возможным решением, которое вы использовали в примере

Вы должны передать параметры param_name, param_age и param_order

 insert 
   into t 
with data
  as (select (max(order) +max(:param_order))/2 as possible_solution 
        from t
        where order<:param_order 
      )
select :param_name,:param_age,d.possible_solution 
  from data d
0 голосов
/ 02 августа 2020

Я думаю, что последовательность в PostgreSQL может решить этот случай

CREATE SEQUENCE serial START 101;

вы можете найти более подробную информацию об этом здесь

https://www.postgresql.org/docs/9.5/sql-createsequence.html

...