作为示例,请考虑此分层架构。
假设所有id字段都是自动递增主键,并且外键由 [parent_table_name] _id 约定命名。
只要数据库中有多家公司,公司就会共享它们之间的所有主键序列。
例如,如果有两个公司行, customer_group 表可能如下所示
| id | company_id |
-------------------
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 1 |
-------------------
但它看起来应该是这样的
| id | company_id |
-------------------
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
-------------------
客户以及树中直接或间接引用公司的任何其他表格也应展示此行为。
请注意,为此,我很可能会创建第二个 id 列(名称类似 relative_id ),并保留唯一的 id 列完整,因为这主要用于显示目的以及用户将如何引用这些数据实体。
现在,如果这只是一个层次结构,那么这将是一个相对简单的解决方案。 我可以创建一个表(table_name,company_id,current_id)和一个在插入任何表之前触发的触发器过程,将当前id递增1并将行的 relative_id 设置为该值。 当插入查询中 company_id 就在那里时,这是微不足道的。
但是那些没有直接引用公司的表怎么样?
与此示例中最低级别的层次结构一样,工作订单,仅引用客户。
是否有一个干净,可重复使用的解决方案,从'customer_id'一直爬到梯子上,最终找回育儿 company_id ?
在每个INSERT上以SELECTs递归递增层次结构对我来说听起来不太吸引人,性能明智。
我也不喜欢只为这些表中的公司添加外键的想法,每个附加表的架构会变得越来越丑。
但这些是我能看到的两种解决方案,但我可能没有找到合适的位置。
答案 0 :(得分:1)
如果您使用生成的密钥,公司不应该关心主键是什么。他们应该毫无意义;比较平等而不是别的。我grumbled about this earlier,所以我很高兴看到你写道:
请注意,我很可能会创建第二个id列(命名为 像relative_id)为此目的,保持唯一的id列 完整,因为这主要是为了显示目的和如何用户 将引用这些数据实体。
你做对了。
大多数时候ID都不重要,所以你可以给它们一些序列中的任何东西,而不关心孔/间隙。如果您担心公司间泄漏(不太可能),您可以使用序列作为伪随机生成器的输入来混淆ID。请参阅DanielVerité几年前回答我关于此问题的函数pseudo_encrypt。
通常有特定的目的,您需要完美的顺序无间隙ID,如发票号码。对于那些你需要使用计数器表的人 - 是的 - 查找公司ID。无论如何,这样的ID生成很慢并且具有可怕的并发性,因此在索引键上具有SELECT
或两个JOIN
的额外SELECT
不会造成太大损害。不要使用JOIN
递归递增模式,只需使用一系列workorder
s。例如,对于插入workorder
, CREATE OR REPLACE FUNCTION workorder_id_tgfn() RETURNS trigger AS $$
BEGIN
IF tg_op = 'INSERT' THEN
-- Get a new ID, locking the row so no other transaction can add a
-- workorder until this one commits or rolls back.
UPDATE workorder_ids
SET next_workorder_id = next_workorder_id + 1
WHERE company_id = (SELECT company_id
FROM customer
INNER JOIN customer_group ON (customer.customer_group_id = customer_group.id)
INNER JOIN company ON (customer_group.company_id = company.id)
WHERE customer.id = NEW.customer_id)
RETURNING next_workorder_id
INTO NEW.id;
END IF;
END;
$$ LANGUAGE 'plpgsql';
上的密钥生成触发器将类似于(未经测试):
UPDATE ... RETURNING ... INTO
对于CREATE TABLE demo (id serial primary key, blah text);
BEGIN;
INSERT INTO demo(blah) values ('aa');
COMMIT;
BEGIN;
INSERT INTO demo(blah) values ('bb');
ROLLBACK;
BEGIN;
INSERT INTO demo(blah) values ('aa');
COMMIT;
SELECT * FROM demo;
语法,请参阅Executing a Query with a Single-Row Result。
即使没有多公司问题,正常序列也可能存在差距。观察:
regress=# SELECT * FROM demo;
id | blah
----+------
1 | aa
3 | aa
结果:
{{1}}
答案 1 :(得分:0)
“但它应该看起来像这样”
| id | company_id |
-------------------
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
-------------------
我认为不应该,我认为你想要多对多的关系。 customer_group表:
| id | name |
-------------
| 1 | n1 |
| 2 | n2 |
| 3 | n3 |
-------------
然后是customer_group_company表:
| group_id | company_id |
-------------------------
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
-------------------------