我的问题是对Erwin Brandstetter在本主题中有关正确使用的出色回答的某种扩展WITH。
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_name或rm_name在表空import。所以我的理论方法是这样的:
r
d
d_id
r_id
z
dm_name
rm_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告诉我:
“ INSERT INTO端口(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设备或d设备,而不能具有任何设备,因此引入z表时,端口表中只有一个字段代表所有可能性。d / r和dm / rm表无法合并,因为它们具有不同的特殊列,具体取决于设备类型。
您不能INSERT在CASE表达式中嵌套语句。从我所看到的结果来看,这种完全不同的方法应该做到这一点:
INSERT
CASE
您实际上不需要外部的SELECT。
SELECT
dm_name/rm_name定义独特在dm/rm和不为空(<> '')。您应该有一个CHECK约束来确保。
dm
rm
<> ''
CHECK
d_id和r_idin的列默认z均为NULL(默认)。
如果两者从未同时出现。
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产生一个派生表,该表具有来自另一行的所有行,d1并在r1其后附加NULL(两者之间没有重叠)。因此,我们只需要一个INSERT而不是两个。次要优化。
FULL JOIN .. ON FALSE
d1
r1
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不返回行,则不插入任何内容。
如果必须处理可能与该操作冲突的并发写访问,则快速解决方案是在同一事务中运行此语句之前,锁定涉及的表。