如何创建一个根据另一列的值增加的列
How create a column that increase according to the value of another column
我有一个table,我想把所有关于文章使用的信息放在这里,我需要创建一个自动增量的列,如果字段ID
可以有相同的值(tipo
) 有另一个值,对于这个特定的 ID
是唯一的。例如:
ID / TIPO
1 / AJE -- Is Ok
1 / AJS -- Is Ok (because this Tipo is AJS, different from AJE)
1 / SI -- Is Ok
2 / AJE -- Is Ok (New ID)
2 / AJE -- Is Wrong, because ID=2, TIPO=AJE already exist.
我已经完成了独特的句子:
ALTER TABLE public.art_movimientos
ADD CONSTRAINT uk_mov UNIQUE (id,tipo) USING INDEX TABLESPACE sistema_index;
但是如何创建覆盖两列的自动增量?
我的table代码:
CREATE TABLE public.art_movimientos
(
id integer NOT NULL DEFAULT nextval('seq_art_movimientos'::regclass),
tipo character(3) NOT NULL, -- Tipos de Valores:...
documento integer,
fecha_doc date[] NOT NULL,
fecha_mov date[] NOT NULL,
calmacen integer NOT NULL,
status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE...
mes integer NOT NULL,
"año" integer NOT NULL,
donado integer NOT NULL DEFAULT 0
)
WITH (
OIDS=FALSE
);
您可以通过使用 before insert 触发器来管理这种情况,模仿@dhke 所述的行为:
CREATE TABLE art_movimientos
(
id integer NOT NULL DEFAULT NULL, -- You don't want a serial, nor a default
tipo character(3) NOT NULL, -- Tipos de Valores:...
documento integer,
fecha_doc date[] NOT NULL,
fecha_mov date[] NOT NULL,
calmacen integer NOT NULL,
status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE...
mes integer NOT NULL,
"año" integer NOT NULL,
donado integer NOT NULL DEFAULT 0,
/* You have actually a 2-column Primary Key */
PRIMARY KEY (tipo, id)
);
-- Create a trigger function to generate 'id'
CREATE FUNCTION art_movimientos_insert_trigger()
RETURNS trigger
AS
$$
BEGIN
/* Compute "id", as the following id for a certain "tipo" */
new.id = coalesce(
(SELECT max(id) + 1
FROM art_movimientos a
WHERE a.tipo = new.tipo), 1);
return new;
END
$$
LANGUAGE 'plpgsql'
VOLATILE ;
-- This trigger will be called whenever a new row is inserted, and "id" is
-- not specified (i.e.: it defaults to null), or is specified as null
CREATE TRIGGER art_movimientos_ins_trg
BEFORE INSERT
ON art_movimientos
FOR EACH ROW
WHEN (new.id IS NULL)
EXECUTE PROCEDURE art_movimientos_insert_trigger();
然后您可以插入以下行(无需 指定 id
列):
INSERT INTO art_movimientos
(tipo, documento, fecha_doc, fecha_mov, calmacen, mes, "año")
VALUES
('AJE', 1, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJS', 2, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('SI', 3, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJE', 4, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJE', 5, array['20170128'::date], array['20170128'::date], 1, 1, 2017) ;
... 看看你得到了你想要的:
SELECT
id, tipo
FROM
art_movimientos
ORDER BY
documento ;
| id | tipo |
|----|------|
| 1 | AJE |
| 1 | AJS |
| 1 | SI |
| 2 | AJE |
| 3 | AJE |
您可以检查所有内容 SQLFiddle(对 PL/pgSQL 函数和分号有点挑剔)。
旁注:在一些极端情况下,由于死锁 [=40=,此过程可能会在事务中失败] 竞争条件,如果其他事务也在同时向同一个table插入数据。因此,您的整体代码应该能够处理中止的事务,并重试它们或向用户显示错误。
我有一个table,我想把所有关于文章使用的信息放在这里,我需要创建一个自动增量的列,如果字段ID
可以有相同的值(tipo
) 有另一个值,对于这个特定的 ID
是唯一的。例如:
ID / TIPO
1 / AJE -- Is Ok
1 / AJS -- Is Ok (because this Tipo is AJS, different from AJE)
1 / SI -- Is Ok
2 / AJE -- Is Ok (New ID)
2 / AJE -- Is Wrong, because ID=2, TIPO=AJE already exist.
我已经完成了独特的句子:
ALTER TABLE public.art_movimientos
ADD CONSTRAINT uk_mov UNIQUE (id,tipo) USING INDEX TABLESPACE sistema_index;
但是如何创建覆盖两列的自动增量?
我的table代码:
CREATE TABLE public.art_movimientos
(
id integer NOT NULL DEFAULT nextval('seq_art_movimientos'::regclass),
tipo character(3) NOT NULL, -- Tipos de Valores:...
documento integer,
fecha_doc date[] NOT NULL,
fecha_mov date[] NOT NULL,
calmacen integer NOT NULL,
status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE...
mes integer NOT NULL,
"año" integer NOT NULL,
donado integer NOT NULL DEFAULT 0
)
WITH (
OIDS=FALSE
);
您可以通过使用 before insert 触发器来管理这种情况,模仿@dhke 所述的行为:
CREATE TABLE art_movimientos
(
id integer NOT NULL DEFAULT NULL, -- You don't want a serial, nor a default
tipo character(3) NOT NULL, -- Tipos de Valores:...
documento integer,
fecha_doc date[] NOT NULL,
fecha_mov date[] NOT NULL,
calmacen integer NOT NULL,
status character(13) NOT NULL DEFAULT 'PENDIENTE'::bpchar, -- PENDIENTE...
mes integer NOT NULL,
"año" integer NOT NULL,
donado integer NOT NULL DEFAULT 0,
/* You have actually a 2-column Primary Key */
PRIMARY KEY (tipo, id)
);
-- Create a trigger function to generate 'id'
CREATE FUNCTION art_movimientos_insert_trigger()
RETURNS trigger
AS
$$
BEGIN
/* Compute "id", as the following id for a certain "tipo" */
new.id = coalesce(
(SELECT max(id) + 1
FROM art_movimientos a
WHERE a.tipo = new.tipo), 1);
return new;
END
$$
LANGUAGE 'plpgsql'
VOLATILE ;
-- This trigger will be called whenever a new row is inserted, and "id" is
-- not specified (i.e.: it defaults to null), or is specified as null
CREATE TRIGGER art_movimientos_ins_trg
BEFORE INSERT
ON art_movimientos
FOR EACH ROW
WHEN (new.id IS NULL)
EXECUTE PROCEDURE art_movimientos_insert_trigger();
然后您可以插入以下行(无需 指定 id
列):
INSERT INTO art_movimientos
(tipo, documento, fecha_doc, fecha_mov, calmacen, mes, "año")
VALUES
('AJE', 1, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJS', 2, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('SI', 3, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJE', 4, array['20170128'::date], array['20170128'::date], 1, 1, 2017),
('AJE', 5, array['20170128'::date], array['20170128'::date], 1, 1, 2017) ;
... 看看你得到了你想要的:
SELECT
id, tipo
FROM
art_movimientos
ORDER BY
documento ;
| id | tipo |
|----|------|
| 1 | AJE |
| 1 | AJS |
| 1 | SI |
| 2 | AJE |
| 3 | AJE |
您可以检查所有内容 SQLFiddle(对 PL/pgSQL 函数和分号有点挑剔)。
旁注:在一些极端情况下,由于死锁 [=40=,此过程可能会在事务中失败] 竞争条件,如果其他事务也在同时向同一个table插入数据。因此,您的整体代码应该能够处理中止的事务,并重试它们或向用户显示错误。