我试图建立一个排序的博客系统,但我遇到了一个小问题。
简单地说,我的article
表中有3列:
id SERIAL,
category VARCHAR FK,
category_id INT
id
列显然是PK,它被用作所有文章的全局标识符。
category
列很好..类别。
category_id
用作类别中的UNIQUE
ID,因此目前存在UNIQUE(category, category_id)
约束。
但是,我还希望category_id
自动增加。
我希望每次执行像
这样的查询时都这样INSERT INTO article(category) VALUES ('stackoverflow');
我希望根据' stackoverflow'的最新category_id
自动填充category_id
列。类别。
在我的逻辑代码中实现这一点非常简单。我只选择最新的num并插入+1,但这涉及两个单独的查询。 我正在寻找一个可以在一个查询中完成所有这些操作的SQL解决方案。
答案 0 :(得分:5)
至少有几种方法可以解决这个问题。我想到的第一个:
通过覆盖category_id
语句中的输入值,为每行执行的触发器中的INSERT
列分配值。
在这里 SQL Fiddle 查看实际操作中的代码
对于简单的测试,我创建了article
表格保留类别及其id
个,这些类别对于每个category
都应该是唯一的。我省略了约束创建 - 这与提出要点无关。
create table article ( id serial, category varchar, category_id int )
使用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
创建一个触发器函数,该函数将选择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;
$$
将此功能用作触发器。
CREATE TRIGGER trg_category_increment
BEFORE INSERT ON article
FOR EACH ROW EXECUTE PROCEDURE category_increment()
为现有类别和不存在的类别插入更多值(后触发设备)。
INSERT INTO article(category) VALUES
('stackoverflow'),
('stackexchange'),
('nonexisting');
用于选择数据的查询:
select category, category_id From article order by 1,2
初始插入的结果:
category category_id
stackexchange 1
stackexchange 2
stackexchange 3
stackoverflow 1
最终插入后的结果:
category category_id
nonexisting 1
stackexchange 1
stackexchange 2
stackexchange 3
stackexchange 4
stackoverflow 1
stackoverflow 2
答案 1 :(得分:5)
这已被多次询问,并且一般的想法在多用户环境中一定会失败 - 并且博客系统听起来就是这样的情况。
所以最好的答案是:不要。考虑一种不同的方法。
完全从表中删除 列 - 它不存储其他两列category_id
(id, category)
已经存储的信息。
您的id
是serial
列,并且已经可靠地自动递增。
如果您需要某种category_id
而不是category
的差距,请使用row_number()
动态生成
答案 2 :(得分:-1)
Postgresql使用序列来实现这一目标;它与您在MySQL中习惯的方法不同。请查看http://www.postgresql.org/docs/current/static/sql-createsequence.html以获取完整参考。
基本上你通过以下方式创建一个序列(数据库对象):
CREATE SEQUENCE serials;
然后当你想要添加到你的桌子时,你将拥有:
INSERT INTO mytable (name, id) VALUES ('The Name', NEXTVAL('serials')