ymc*_*331 10 sql postgresql database-design auto-increment
我正在尝试建立一个排序的博客系统,我遇到了一个小问题.
简单地说,我的article
表中有3列:
id SERIAL,
category VARCHAR FK,
category_id INT
Run Code Online (Sandbox Code Playgroud)
id
column显然是PK,它被用作所有文章的全局标识符.
category
列很好..类别.
category_id
用作UNIQUE
类别中的ID,因此目前存在UNIQUE(category, category_id)
约束.
不过,我也想为category_id
以自动递增.
我想要它,以便每次我执行像这样的查询
INSERT INTO article(category) VALUES ('stackoverflow');
Run Code Online (Sandbox Code Playgroud)
我希望category_id
根据最新category_id
的"stackoverflow"类别自动填充列.
在我的逻辑代码中实现这一点非常容易.我只选择最新的num并插入+1,但这涉及两个单独的查询.我正在寻找一个可以在一个查询中完成所有这些的SQL解决方案.
这已被多次询问,并且一般的想法在多用户环境中肯定会失败 - 博客系统听起来就是这样的情况.
所以最好的答案是:不要.考虑一种不同的方法.
将列完全从表中删除- 它不会存储其他两列不会存储的任何信息category_id
(id, category)
.
您id
是一个serial
专栏,并且已经以可靠的方式自动递增.
如果您需要某种category_id
无间隙category
,请在运行时生成row_number()
:
至少有几种方法可以解决这个问题.我想到的第一个:
category_id
通过覆盖INSERT
语句中的输入值,为每行执行的触发器内的列分配值.
这是SQL Fiddle看到代码的实际应用
对于一个简单的测试,我正在创建article
表格保持类别,并且id
每个类别应该是唯一的category
.我省略了约束创建 - 这与提出要点无关.
create table article ( id serial, category varchar, category_id int )
Run Code Online (Sandbox Code Playgroud)
使用generate_series()
函数为两个不同的类别插入一些值以使其具有自动增量.
insert into article(category, category_id)
select 'stackoverflow', i from generate_series(1,1) i
union all
select 'stackexchange', i from generate_series(1,3) i
Run Code Online (Sandbox Code Playgroud)
创建一个触发器函数,它将选择MAX(category_id)
并递增其值,1
因为category
我们正在插入一行,然后在继续使用实际INSERT
到表之前覆盖该值(BEFORE INSERT
触发器负责处理).
CREATE OR REPLACE FUNCTION category_increment()
RETURNS trigger
LANGUAGE plpgsql
AS
$$
DECLARE
v_category_inc int := 0;
BEGIN
SELECT MAX(category_id) + 1 INTO v_category_inc FROM article WHERE category = NEW.category;
IF v_category_inc is null THEN
NEW.category_id := 1;
ELSE
NEW.category_id := v_category_inc;
END IF;
RETURN NEW;
END;
$$
Run Code Online (Sandbox Code Playgroud)
使用该功能作为触发器.
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
Run Code Online (Sandbox Code Playgroud)
为现有类别和不存在的类别插入更多值(后触发设备).
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
Run Code Online (Sandbox Code Playgroud)
用于选择数据的查询:
select category, category_id From article order by 1,2
Run Code Online (Sandbox Code Playgroud)
初始插入的结果:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
Run Code Online (Sandbox Code Playgroud)
最终插入后的结果:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
Run Code Online (Sandbox Code Playgroud)