gpt4 book ai didi

sql - 将数据修改 CTE 中的 INSERT 语句与 CASE 表达式相结合

转载 作者:行者123 更新时间:2023-11-29 12:04:58 25 4
gpt4 key购买 nike

我的问题是对 Erwin Brandstetter 在 this thread 中出色回答的某种扩展WITH 的正确使用。

我的旧查询如下所示:

WITH x AS (
INSERT INTO d (dm_id)
SELECT dm_id
FROM dm, import i
WHERE dm.dm_name = i.dm_name
RETURNING d_id
), y AS (
INSERT INTO z (d_id)
SELECT d_id
FROM x
RETURNING z_id
)
INSERT INTO port (z_id)
SELECT z_id
FROM y;

这就像一个魅力。但是现在,添加了另一个表 (r)(与表 d 的结构相同),并且 d_id 的可能性>r_id 必须添加到表 z。这取决于 dm_namerm_name 在表 import 中是否为空。所以我的理论方法是这样的:

SELECT dm_name, rm_name

,CASE WHEN dm_name != '' THEN
WITH x AS (
INSERT INTO d (dm_id)
SELECT dm_id
FROM dm, import i
WHERE dm.dm_name = i.dm_name
RETURNING d_id
), y AS (
INSERT INTO z (d_id)
SELECT d_id
FROM x
RETURNING z_id
)
INSERT INTO port (z_id)
SELECT z_id
FROM y
END

,CASE WHEN rm_name != '' THEN
WITH x AS (
INSERT INTO r (rm_id)
SELECT rm_id
FROM rm, import i
WHERE rm.rm_name = i.rm_name
RETURNING r_id
), y AS (
INSERT INTO z (r_id)
SELECT r_id
FROM x
RETURNING z_id
)
INSERT INTO port (z_id)
SELECT z_id
FROM y
END

FROM import;

但是 PostgreSQL 告诉我:

syntax error at or near "INSERT INTO port (z_id)"

虽然查询的那部分应该是正确的,因为它已经可以工作了。
我希望你能帮我解决这个问题。 :)

为了更好地理解 - 这是表格结构:

CREATE TABLE import (
dm_name character varying,
rm_name character varying
-- many other columns which are not relevant
);

CREATE TABLE dm (
dm_id integer NOT NULL, -- serial
dm_name character varying
-- plus more columns
);

CREATE TABLE d (
d_id integer NOT NULL, -- serial
dm_id integer -- references dm.dm_id
-- plus more columns
);

CREATE TABLE rm (
rm_id integer NOT NULL, -- serial
rm_name character varying
-- plus more columns
);

CREATE TABLE r (
r_id integer NOT NULL, -- serial
rm_id integer -- references rm.rm_id
-- plus more columns
);

CREATE TABLE z (
z_id integer NOT NULL, -- serial
r_id integer, -- references r.r_id
d_id integer -- references d.d_id
-- plus more columns
);

CREATE TABLE port (
p_id integer NOT NULL, -- serial
z_id integer, -- references z.z_id
-- plus more columns
);

导入表不知道这些 ID,因为它们是在原子化过程中生成的。 dm 和 rm 表用于已从导入表中提取的设备模型。 d 和 r 表用于实际设备。由于一个端口只能有一个 r-device 或一个 d-device 或没有,因此引入了 z-table 以在端口表中只有一个字段代表所有可能性。 d/r 和 dm/rm 表不能合并,因为它们根据设备类型具有不同的特殊列。

最佳答案

你不能嵌套INSERT CASE 中的语句表达。根据我的观察,这种完全不同的方法应该可以做到:

假设

  • 你实际上并不需要外层的 SELECT .

  • dm_name/rm_namedm 中定义为唯一/rm并且不为空( <> '' )。你应该有一个 CHECK约束以确保。

  • 两者的列默认值 d_idr_idz为 NULL(默认)。

dm_namerm_name互斥

如果两者从未同时出现。

WITH d1 AS (
INSERT INTO d (dm_id)
SELECT dm.dm_id
FROM import
JOIN dm USING (dm_name)
RETURNING d_id
)
, r1 AS (
INSERT INTO r (rm_id)
SELECT rm.rm_id
FROM import
JOIN rm USING (rm_name)
RETURNING r_id
)
, z1 AS (
INSERT INTO z (d_id, r_id)
SELECT d_id, r_id
FROM d1 FULL JOIN r1 ON FALSE
RETURNING z_id
)
INSERT INTO port (z_id)
SELECT z_id
FROM z1;

FULL JOIN .. ON FALSE生成包含所有行的派生表 d1r1为相应的其他列附加 NULL(两者之间没有重叠)。所以我们只需要一个 INSERT而不是两个。小幅优化。

dm_namerm_name可以共存

WITH i AS (
SELECT dm.dm_id, rm.rm_id
FROM import
LEFT JOIN dm USING (dm_name)
LEFT JOIN rm USING (rm_name)
)
, d1 AS (
INSERT INTO d (dm_id)
SELECT dm_id FROM i WHERE dm_id IS NOT NULL
RETURNING dm_id, d_id
)
, r1 AS (
INSERT INTO r (rm_id)
SELECT rm_id FROM i WHERE rm_id IS NOT NULL
RETURNING rm_id, r_id
)
, z1 AS (
INSERT INTO z (d_id, r_id)
SELECT d1.d_id, r1.r_id
FROM i
LEFT JOIN d1 USING (dm_id)
LEFT JOIN r1 USING (rm_id)
WHERE d1.dm_id IS NOT NULL OR
r1.rm_id IS NOT NULL
RETURNING z_id
)
INSERT INTO port (z_id)
SELECT z_id FROM z1;

注意事项

如果两个版本都不存在,也可以使用。

INSERT如果 SELECT 则不插入任何内容不返回行。

如果您必须处理可能与此操作冲突的并发写访问,快速解决方法是在同一事务中运行此语句之前锁定涉及的表。

关于sql - 将数据修改 CTE 中的 INSERT 语句与 CASE 表达式相结合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28992241/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com