Kev*_*son 5 postgresql postgresql-9.5
我正在尝试编写查询以将文件名插入下表 path
CREATE SEQUENCE path_id_seq;
CREATE TABLE path (
id INTEGER PRIMARY KEY DEFAULT NEXTVAL('path_id_seq'),
parent_id INTEGER,
name TEXT NOT NULL);
CREATE UNIQUE INDEX path_parent_id_name_ix
ON path (COALESCE(parent_id, 0), name);
ALTER TABLE path
ADD CONSTRAINT ios_path_parent_id_fk
FOREIGN KEY (parent_id) REFERENCES path (id)
ON DELETE CASCADE
DEFERRABLE INITIALLY DEFERRED;
Run Code Online (Sandbox Code Playgroud)
例如,给定文件名Assets/images/a.png
,Assets/images/b.png
我想插入以下行。
id | parent_id | name
----+-----------+-------------------
1 | ¤ | Assets
2 | 1 | images
3 | 2 | a.png
4 | 2 | b.png
Run Code Online (Sandbox Code Playgroud)
插入父对象很容易;
INSERT INTO path (name)
VALUES ('Assets')
ON CONFLICT (COALESCE(parent_id, 0), name)
DO UPDATE SET name = EXCLUDED.name -- this strange update is so that we get rows back
RETURNING id, parent_id, name;
Run Code Online (Sandbox Code Playgroud)
产生;
id | parent_id | name
----+-----------+--------
1 | ¤ | Assets
Run Code Online (Sandbox Code Playgroud)
但是我似乎无法将递归 CTE 放在一起以在下一个 INSERT 语句中使用父代的 id 作为 parent_id。
它可能看起来像下面这个无效的查询。
WITH RECURSIVE names AS (
SELECT name, lag(name, 1) OVER () as previous_name
FROM (SELECT unnest(string_to_array('Assets/images/232.png', '/')) as name) names),
paths(id, name) AS (
INSERT INTO path (name)
SELECT name
FROM names
WHERE previous_name IS NULL
ON CONFLICT (COALESCE(parent_id, 0), name)
DO UPDATE SET name = EXCLUDED.name
RETURNING id, name
UNION
INSERT INTO path (parent_id, name)
SELECT paths.id, names.name
FROM paths
JOIN names ON names.previous_name = paths.name
ON CONFLICT (COALESCE(parent_id, 0), name)
DO UPDATE SET name = EXCLUDED.name
RETURNING id, name)
SELECT *
FROM paths;
Run Code Online (Sandbox Code Playgroud)
但我似乎无法让它发挥作用。如果有人看到一种更简单的方法来做到这一点,我们将不胜感激。
小智 4
您不需要递归 CTE,您可以直接nextval()
在结果中使用unnest()
,然后使用lag()
从上一行获取值。为了处理现有行,我将使用 unnest() 的结果和路径表之间的联接来执行此操作,检测新行和现有行。
对于新行,将生成一个新 ID,并且仅插入这些 ID:
insert into path (id, name, parent_id)
select id, name, parent_id
from (
select *,
case
when is_new
then lag(id) over (order by level)
else existing_parent
end as parent_id
from (
SELECT case
when p.id is null then nextval('path_id_seq')
else p.id
end as id,
x.name, x.level, p.parent_id as existing_parent,
p.id is null as is_new
FROM unnest(string_to_array('Assets/images/232.png', '/')) with ordinality as x(name, level)
LEFT JOIN path p on p.name = x.name
order by level
) t1
) t2
where is_new;
Run Code Online (Sandbox Code Playgroud)
实例: http: //rextester.com/YGMT19565
如果您愿意的话,唯一的“缺点”是序列值不一定按照您期望的“顺序”分配。但由于生成的主键的唯一目的是唯一(而不是其他),这不应该成为问题。
归档时间: |
|
查看次数: |
2060 次 |
最近记录: |