在Postgres 9.2中是否有办法创建一个聚合来自两个表的数据的视图,其中涉及一些逻辑?
我们需要的逻辑是:
key
的后续行(多个字段的组合)会覆盖以前的行。D
的行会删除给定“密钥”的前任行。我在Postgres数据库中有2个模式。它们每个都有相同的表和列,但数据不同。一个用于官方数据,一个用于建议的更改。
注意:我确信有更好的方法,但这是一个传统设置,无法更改。这是一个非常简化的,虚构的例子,但显示了我需要的情况和结果。
所以我们有一个描述小部件的特征表。官方数据中只有一种数据类型(小部件将具有一种尺寸,一种颜色等)。
提议的更改一旦获得批准,就会更改官方数据。对于给定类型的数据,可能存在多个挂起的更改。
official
架构CREATE TABLE characteristics (
widget_id integer NOT NULL,
variation_id integer NOT NULL,
value varchar(10),
action_date date,
status char(1)
);
official.characteristics
中的示例数据:
1,1,GI Joe,12/25/2012,C
1,2,Green,12/25/2012,C
1,3,M,12/25/2012,C
1,4,Plastic,12/25/2012,C
2,1,GI Joe,12/25/2012,C
2,2,Green,12/25/2012,C
2,3,L,12/25/2012,C
2,4,Plastic,12/25/2012,C
所以我们有2个小部件,一个是中等,绿色和塑料。一个是大的,绿色的和塑料的。
proposed
架构CREATE TABLE characteristics (
widget_id integer NOT NULL,
variation_id integer NOT NULL,
value varchar(10),
action_date date,
status char(1)
);
proposed.characteristics
中的示例数据:
1,2,Blue,2/22/2013,C
1,4,Plastic,2/22/2013,D
2,2,Purple,2/10/2013,C
2,2,Green,2/22/2013,D
2,3,XL,2/22/2013,C
如果我们想看看所有提议的更改的结果是什么,我们可以查询两个表,更新的数据替换旧的,或D行删除任何先前的更改。
SELECT
'o' as src,
lpad(widget_id::text,4,'0'::text) || '_' || lpad(variation_id::text,4,'0'::text) as key,
*
FROM
proposed.characteristics
ORDER BY
key ASC,
action_date::date ASC
第二个查询是相同的,但在另一个表上,并且'p'作为src。
使用PHP,我可以查询每个表,首先是官方的,然后是第二个建议的更改,并将数据放入一个以key
(widget_id || '_' || variation_id
)为键的数组中。任何新行都会覆盖旧行。如果status
为D
(用于删除),则删除带有密钥的行(尽管后续建议的更改可能会重新添加)。
因此,对于上述数据,我们最终会得到:
o,0001_0001,1,1,GI Joe,12/25/2012,C
p,0001_0002,1,2,Blue,2/22/2013,C
o,0001_0003,1,3,M,12/25/2012,C
o,0002_0001,1,1,GI Joe,12/25/2012,C
p,0002_0003,2,3,XL,2/22/2013,C
o,0002_0004,2,4,Plastic,12/25/2012,C
有没有办法可以创建一个视图,我可以直接查询上面的结果?
仍然有D
用于删除工作,更新的更改会覆盖以前的更改或官方数据吗?
答案 0 :(得分:1)
假设当前版本PostgreSQL 9.2缺乏信息。
执行此操作的一种方法是使用UNION ALL
两个表CTE,并使用NOT EXISTS
反半连接获取每个窗口小部件的最后一个有效版本:
CREATE VIEW my_viw AS
WITH x AS (
SELECT 'o' as src, * FROM official.characteristics
UNION ALL
SELECT 'p' as src, * FROM proposed.characteristics
)
SELECT lpad(widget_id::text, 4, '0')
|| '_' || lpad(variation_id::text, 4, '0') AS key, * -- pick columns
FROM x
WHERE NOT EXISTS (
SELECT 1 FROM x y
WHERE y.widget_id = x.widget_id
AND y.variation_id = x.variation_id
AND y.action_date > x.action_date
)
AND (status <> 'D' OR status IS NULL)
ORDER BY widget_id, variation_id
返回你概述的结果,除了我在评论中指出的错误。
UNION ALL
从两个表中获取所有行NOT EXISTS
status = 'D'
排除行。widget_id, variation_id
合成密钥。使用原始列widget_id, variation_id
进行操作最有可能更快,并且只能在最终key
中合成SELECT
。代码更少,更容易索引。
使用CTE,因为两个地方需要结果。
应该定义status
列NOT NULL
,使WHERE条件更简单。
两个表中的多列索引如下所示可能有助于提高性能。不确定它是否可以在UNION ALL
之后使用。使用EXPLAIN ANALYZE
进行测试以查看。
CREATE INDEX characteristics_mult_idx
ON official.characteristics (widget_id, variation_id, action_date DESC)