这个问题更多的是关于什么是最好的approch来设计一个包含系统中proccess状态的表。
我有一个处于状态的进程:init, waiting for price approve, sent, accepted,finished
状态可以一步一步前进,也可以一步一步前进,这意味着从init
开始,您无法通过sent
跳转到waitig for price approve
。< / p>
我设计了下表(PostgreSQL
,但这对问题并不重要):
CREATE TABLE status
(
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
backid Integer,
forwardid integer,
CONSTRAINT id_pkey PRIMARY KEY (id)
CONSTRAINT backid_fkey FOREIGN KEY (id)
REFERENCES status(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION
CONSTRAINT forward_fkey FOREIGN KEY (id)
REFERENCES status(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION
)
基本上意味着:
id name backid forwardid
1 init 2
2 waiting for price approve 1 3
3 sent 2 4
4 accepted 3 5
5 finished 4
注意:在1
之后,2
将无法获得id name backid forwardid
1 init 3
3 sent 1 4
4 accepted 3 5
5 finished 4
。将来我可以删除其中一行,它可能看起来像这样:
Doubly linked list
它与Doubly linked list
的行为相同。
我们的目标是,如果将来会有一个新的状态,它将被提交到桌面,我不会在其他任何地方进行更改。当客户要求转发/退回时,它将自动完成到新的&#34;列表&#34;状态。
事情是,这种方式似乎有点不优雅。插入新状态将与插入SQL
的算法相同。这看起来似乎太多了,而且$today = date("Ymd");
$args = array(
'post_type' => 'news',
'posts_per_page' => -1,
'meta_key' => 'pinned_news_item',
'meta_value' => '1',
'order' => 'DESC',
'orderby' => $today,
);
和数据库的能力似乎不合适。
你能建议一个更好的方法吗?
答案 0 :(得分:2)
不需要forwardid
,我认为删除它可以让生活更轻松(尽管如果您认为它可以让您的查询更容易,可以保留它)。
但我不会将id
列定义为serial
。我希望在插入和更新期间控制ID。
假设您的表定义,您可以使用recursive common table expression查询整个层次结构,包括某个排序列:
with recursive status_tree as (
select id, name, backid, 1 as level
from status
where backid is null
union all
select c.id, c.name, c.backid, p.level + 1
from status c
join status_tree p on p.id = c.backid
)
select *
from status_tree
order by level;
对于您的样本数据,这将返回:
id | name | backid | level
---+---------------------------+--------+------
1 | init | | 1
2 | waiting ror price approve | 1 | 2
3 | sent | 2 | 3
4 | accepted | 3 | 4
5 | finished | 4 | 5
插入新状态非常简单(这是手动定义的id
使生活更轻松的一点:
-- create a new status that may be set after 'waiting ror price approve'
insert into status (id, name, backid)
values (6, 'partially sent', 2);
-- now make the current 'sent' status an descendant of the new one
update status
set backid = 6
where name = 'sent';
以上查询现在返回以下内容:
id | name | backid | level
---+---------------------------+--------+------
1 | init | | 1
2 | waiting ror price approve | 1 | 2
6 | partially sent | 2 | 3
3 | sent | 6 | 4
4 | accepted | 3 | 5
5 | finished | 4 | 6
状态值的顺序不反映id
列的“顺序”。
如果需要,可以创建一个返回此信息的视图。
修改强>
如果您经常找到 next 状态而不是查看所有这些状态,那么您可以翻转逻辑并仅存储下一个逻辑:
CREATE TABLE status
(
id integer PRIMARY KEY,
name TEXT NOT NULL,
next_status Integer references status
);
insert into status(id, name, next_status)
values
(1,'init', 2),
(2,'waiting ror price approve', 3),
(3,'sent', 4),
(4,'accepted', 5),
(5,'finished', null);
要检索下一个状态,那么只需要一个select
语句(不递归)。
您仍然可以使用CTE以正确的顺序获取所有状态值,您只需要反转连接条件:
with recursive status_tree as (
select id, name, next_status, 1 as level
from status
where id = 1
union all
select c.id, c.name, c.next_status, p.level + 1
from status c
join status_tree p on p.next_status = c.id
)
select *
from status_tree
order by level;
插入新节点的方式与backid
完全相同(只需要“重新链接”“其他”行)
insert into status (id, name, next_status)
values (6, 'partially sent', 3);
update status
set next_status = 6
where name = 'waiting ror price approve';