Есть простая таблица со столбцами a
,b
,c
,d
. Я хочу, чтобы значение в d
было a+b
, если c>0
, и a-b
, если c<=0
. Как я могу это сделать?
Я пробовал этот код, и он не работает. Как я могу динамически вставлять данные в таблицу?
INSERT INTO my_table VALUES(1,2,3,
CASE
WHEN c<0
THEN a+b
ELSE a-b
END
)
У меня есть задача вставить такие данные, и я просто сделал этот пример, чтобы понять, как справиться с этой проблемой. Как я могу сделать это, например, с помощью python?
Мне нужно значение в D (a+b), если C>0, и (a-b), если C<=0. Как я могу это сделать?
Вы не можете ссылаться на столбцы в значениях. Вместо этого вам нужно повторить значения. Предполагая, что вы отправляете запрос на языке программирования, используя параметры привязки...
insert into my_table(a, b, c, d)
values(
$1, $2, $3,
case
when $3 > 0 then $1 + $2
else $1 - $2
)
Вы также можете написать функцию.
-- I want value in D (a+b) if C>0 and (a-b) if C<=0.
create function my_insert(a int, b int, c int)
returns void
language plpgsql
as $$
declare d integer;
begin
case
when c > 0 then d = a + b;
else d = a - b;
end case;
insert into my_table ("a", "b", "c", "d") values (a, b, c, d);
end;
$$
select my_insert(1, 2, 3);
Работая с литеральными значениями, вы можете добиться того же с помощью подзапроса:
INSERT INTO my_table (a,b,c,d)
SELECT *, CASE WHEN c<0 THEN a+b ELSE a-b END AS d
FROM (
VALUES
(3,2, 1) -- input values here, once
, (3,2,-1) -- multiple rows if need be
) sub(a,b,c);
Это работает без явного приведения типов для базовых типов, таких как integer
или text
, поскольку предполагаемые типы по умолчанию для литералов совпадают. Вам может понадобиться явное приведение типов данных для других типов данных в отдельном выражении VALUES
. Видеть:
Более того, избегайте этой проблемы, не сохраняя избыточные данные в таблице с самого начала.
CREATE TABLE my_table (
a int
, b int
, c int
-- NO d; will be computed on the fly
);
INSERT
возвращается к истокам:
INSERT INTO my_table (a,b,c) VALUES
(3,2, 1)
, (3,2, 0)
, (3,2,-1)
;
Дополнительный столбец d
можно дешево вычислить на лету. Обычно намного дешевле, чем чтение большего количества страниц данных из-за увеличения объема памяти:
SELECT *, CASE WHEN c<0 THEN a+b ELSE a-b END AS d
FROM my_table;
Вы можете сохранить логику в VIEW:
CREATE VIEW my_view AS
SELECT *, CASE WHEN c<0 THEN a+b ELSE a-b END AS d
FROM my_table;
SELECT * FROM my_view;
Если вам определенно нужно сохранить вычисленное значение (например, когда вычисления относительно дороги или вы делаете другие вещи со столбцом), используйте сгенерированный столбец STORED (Postgres 12+):
ALTER TABLE my_table
ADD column d int GENERATED ALWAYS AS (CASE WHEN c<0 THEN a+b ELSE a-b END) STORED;
SELECT * my_table;
Видеть:
Спасибо, что предложили сгенерированный столбец! Но в моем проекте у меня была проблема с этим: мне нужен сгенерированный столбец для ссылки на 2 других сгенерированных столбца, и, к сожалению, это вызывает ошибку.
@РоманСвирид: Понятно. Всегда есть исключения из правил ... Также вверху добавлено чистое решение SQL DML.
Скажите, пожалуйста, зачем вам это нужно? Возможно, лучше изменить дизайн таблицы. Также может быть лучше сделать это на языке программирования, а не на SQL.