基于表列的多个自动增量ID

Jas*_*ant 5 sql postgresql database-design auto-increment flask-sqlalchemy

我需要数据库设计方面的帮助。

我有下表。 数据库架构

伪代码:

Table order_status {
  id int[pk, increment]
  name varchar
}

Table order_status_update {
  id int[pk, increment]
  order_id int[ref: > order.id]
  order_status_id int[ref: > order_status.id]
  updated_at datetime
}

Table order_category {
  id int[pk, increment]
  name varchar
}

Table file {
  id int[pk, increment]
  order_id int[ref: > order.id]
  key varchar
  name varchar
  path varchar 
}

Table order {
  id int [pk] // primary key
  order_status_id int [ref: > order_status.id]
  order_category_id int [ref: > order_category.id]
  notes varchar
  attributes json  // no of attributes is not fixed, hence needed a json column
}
Run Code Online (Sandbox Code Playgroud)

一切正常,但现在我需要为每种类型的order_category_id列设置一个自动递增的ID 。

例如,如果我有2类电子产品和玩具,则我需要与1相关的电子产品1,玩具1,玩具2,电子产品2,电子产品3,玩具3,玩具4,玩具5值。order表行。但这是不可能的,因为自动增量是基于每个新行而不是列类型的。

换句话说,用table order代替

  id  order_category_id
---------------------
  1       1       
  2       1       
  3       1     
  4       2       
  5       1      
  6       2
  7       1
Run Code Online (Sandbox Code Playgroud)

我需要关注

 id  order_category_id pretty_ids
----------------------------
  1       1       toy-1
  2       1       toy-2
  3       1       toy-3
  4       2       electronics-1
  5       1       toy-4
  6       2       electronics-2
  7       1       toy-5
Run Code Online (Sandbox Code Playgroud)

我试过的

我为每个订单类别创建了单独的表格(这不是理想的解决方案,但目前我有6个订单类别,因此现在可以使用)

现在,我有electronics_order和的表格toys_order。列是重复的,但可以。但是现在我有另一个问题,我与其他表的每一个关系都被毁了。因为,无论是electronics_ordertoys_orders可以有相同的ID,我不能使用id列于参考order_status_updateorder_statusfile表。我可以order_category在每个表中创建另一列,但这是正确的方法吗?我没有数据库设计方面的经验,所以我想知道其他人是如何做到的。

我也有一个补充问题。

我需要为表order_categoryorder_status刚刚存储的名字呢?因为这些值不会有太大变化,所以我可以将它们存储在代码中并保存在表的列中order

我知道单独的表是柔韧性好,但我不得不查询数据库2次抓取order_statusorder_category通过名称插入新行之前order表。稍后它将是用于查询order表的多个联接。

-

如果有帮助,我将在后端使用flask-sqlalchemy,并将postgresql用作数据库服务器。

Yar*_*red 5

为了跟踪基于的增量ID order_category,我们可以在另一个表上跟踪此值。让我们将此表称为:order_category_sequence。为了展示我的解决方案,我刚刚使用创建了order表格的简化版本order_category

CREATE TABLE order_category (
  id SERIAL PRIMARY KEY,
  name  VARCHAR(100) NULL
); 


CREATE TABLE order_category_sequence (
  id SERIAL PRIMARY KEY,
  order_category_id int NOT NULL,
  current_key  int not null
);

Alter Table order_category_sequence Add Constraint "fk_order_category_id" FOREIGN KEY (order_category_id) REFERENCES order_category (id);
Alter Table order_category_sequence Add Constraint "uc_order_category_id" UNIQUE (order_category_id);


CREATE TABLE "order" (
  id SERIAL PRIMARY KEY,
  order_category_id int NOT NULL,
  pretty_id  VARCHAR(100)  null
);

Alter Table "order" Add Constraint "fk_order_category_id" FOREIGN KEY (order_category_id) REFERENCES order_category (id);
Run Code Online (Sandbox Code Playgroud)

表格中的order_category_idorder_category_sequenceorder_category。该current_key列包含中的最后一个值order

添加新订单行后,我们可以使用触发器从中读取最后一个值order_category_sequence并进行更新pretty_id。以下触发器定义可用于实现此目的。

--function called everytime a new order is added
CREATE OR REPLACE FUNCTION on_order_created()
  RETURNS trigger AS
$BODY$

DECLARE 
current_pretty_id varchar(100);

BEGIN

-- increment last value of the corresponding order_category_id in the sequence table
Update order_category_sequence
set current_key = (current_key + 1)
where order_category_id = NEW.order_category_id;

--prepare the pretty_id
Select 
oc.name || '-' || s.current_key AS   current_pretty_id 
FROM    order_category_sequence AS s
JOIN order_category AS oc on s.order_category_id = oc.id
WHERE s.order_category_id = NEW.order_category_id
INTO current_pretty_id;

--update order table
Update "order"
set pretty_id = current_pretty_id
where id = NEW.id;


RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;


CREATE TRIGGER order_created
  AFTER INSERT
  ON "order"
  FOR EACH ROW
  EXECUTE PROCEDURE on_order_created();
Run Code Online (Sandbox Code Playgroud)

如果要同步两个表order_categoryorder_category_sequence,则每次添加新的订单类别时,可以使用另一个触发器在后一个表中有一行。

//function called everytime a new order_category is added
CREATE OR REPLACE FUNCTION on_order_category_created()
  RETURNS trigger AS
$BODY$

BEGIN
--insert a new row for the newly inserted order_category
Insert into order_category_sequence(order_category_id, current_key)
values (NEW.id, 0);

RETURN NEW;
END;
$BODY$ LANGUAGE plpgsql;


CREATE TRIGGER order_category_created
  AFTER INSERT
  ON order_category
  FOR EACH ROW
  EXECUTE PROCEDURE on_order_category_created();
Run Code Online (Sandbox Code Playgroud)

测试查询和结果:

Insert into order_category(name)
values ('electronics'),('toys');

Insert into "order"(order_category_id)
values (1),(2),(2);


select * from "order";
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

关于您的另一个问题,我更喜欢将查找值(例如order_status和order_category)存储在单独的表中。这样做可以具有上述灵活性,并且当我们进行更改时很容易。


Old*_*Pro 2

回答你的附带问题:是的,出于多种原因,你应该保留包含姓名的表格。首先,此类表很小,并且通常由数据库保存在内存中,因此不使用这些表的性能优势可以忽略不计。其次,您希望能够使用外部工具来查询数据库并生成报告,并且您希望这些工具可以使用这些类型的标签。第三,您希望最大限度地减少软件与实际数据的耦合,以便它们能够独立发展。添加新类别不需要修改您的软件。

现在,对于主要问题,没有内置工具可以实现您想要的自动增量类型。你必须自己构建它。

我建议您将每个类别的序列号保留为类别表中的一列。然后您可以更新它并在订单表中使用更新后的序列号,如下所示(这是 PostgreSQL 特有的):

-- set up the tables

create table orders (
  id SERIAL PRIMARY KEY,
  order_category_id int,
  pretty_id VARCHAR
);
create unique index order_category_pretty_id_idx 
  on orders (pretty_id);

create table order_category (
  id SERIAL PRIMARY KEY,
  name varchar NOT NULL,
  seq int NOT NULL default 0
);

-- create the categories
insert into order_category
(name) VALUES
('toy'), ('electronics');


-- create orders, specifying the category ID and generating the pretty ID

WITH 
  new_category_id (id) AS (VALUES (1)), -- 1 here is the category ID for the new order
  pretty AS (
    UPDATE order_category 
    SET seq = seq + 1
    WHERE id = (SELECT id FROM new_category_id)
    RETURNING *
  )
INSERT into orders (order_category_id, pretty_id)
SELECT new_category_id.id, concat(pretty.name, '-', pretty.seq) 
FROM new_category_id, pretty;

Run Code Online (Sandbox Code Playgroud)

您只需将您的类别 ID 插入我1在示例中的位置,它就会pretty_id为该类别创建新的类别。第一个类别是玩具 1,下一个类别是玩具 2,依此类推。

| id  | order_category_id | pretty_id     |
| --- | ----------------- | ------------- |
| 1   | 1                 | toy-1         |
| 2   | 1                 | toy-2         |
| 3   | 2                 | electronics-1 |
| 4   | 1                 | toy-3         |
| 5   | 2                 | electronics-2 |

Run Code Online (Sandbox Code Playgroud)