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_order和toys_orders可以有相同的ID,我不能使用id列于参考order_status_update,order_status,file表。我可以order_category在每个表中创建另一列,但这是正确的方法吗?我没有数据库设计方面的经验,所以我想知道其他人是如何做到的。
我也有一个补充问题。
我需要为表order_category和order_status刚刚存储的名字呢?因为这些值不会有太大变化,所以我可以将它们存储在代码中并保存在表的列中order。
我知道单独的表是柔韧性好,但我不得不查询数据库2次抓取order_status并order_category通过名称插入新行之前order表。稍后它将是用于查询order表的多个联接。
-
如果有帮助,我将在后端使用flask-sqlalchemy,并将postgresql用作数据库服务器。
为了跟踪基于的增量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_id栏order_category_sequence指order_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_category和order_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)存储在单独的表中。这样做可以具有上述灵活性,并且当我们进行更改时很容易。
回答你的附带问题:是的,出于多种原因,你应该保留包含姓名的表格。首先,此类表很小,并且通常由数据库保存在内存中,因此不使用这些表的性能优势可以忽略不计。其次,您希望能够使用外部工具来查询数据库并生成报告,并且您希望这些工具可以使用这些类型的标签。第三,您希望最大限度地减少软件与实际数据的耦合,以便它们能够独立发展。添加新类别不需要修改您的软件。
现在,对于主要问题,没有内置工具可以实现您想要的自动增量类型。你必须自己构建它。
我建议您将每个类别的序列号保留为类别表中的一列。然后您可以更新它并在订单表中使用更新后的序列号,如下所示(这是 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)