(这是Merge table results into columns (pivot/crosstab?))的后续问题
我有~30个桌子,其中包含#34;流式传输"来自外部系统的数据。我试图弄清楚如何将收集的数据合并到一个查询结果中。
让我们来描述表格布局:
CREATE TABLE IF NOT EXISTS table1 (
id1 INT NOT NULL,
id2 TEXT NOT NULL,
update_time TIMESTAMP(6) NOT NULL,
val NUMERIC NULL,
PRIMARY KEY (id1, id2, update_time)
);
CREATE TABLE IF NOT EXISTS table2 (
id1 INT NOT NULL,
id2 TEXT NOT NULL,
update_time TIMESTAMP(6) NOT NULL,
val INT NULL,
PRIMARY KEY (id1, id2, update_time)
);
--...tableN(
INSERT INTO table1(id1, id2, update_time, val) VALUES (1, 'ident 1', '2004-10-19 09:00:00', 1.23);
INSERT INTO table1(id1, id2, update_time, val) VALUES (1, 'ident 1', '2004-10-19 10:05:00', 1.25);
INSERT INTO table2(id1, id2, update_time, val) VALUES (1, 'ident 1', '2004-10-19 10:03:00', 23);
INSERT INTO table2(id1, id2, update_time, val) VALUES (1, 'ident 1', '2004-10-19 10:03:30', null);
INSERT INTO table2(id1, id2, update_time, val) VALUES (1, 'ident 1', '2004-10-19 10:05:00', 42);
是否可以在特定时间组合所有"已知数据"来自单个查询中的所有表?类似的东西:
SELECT update_time, t1_val, t2_val
FROM combined_output
WHERE start_time = '2004-10-19 08:00:00'
AND end_time = '2004-10-19 12:00:00'
哪会得到结果:
time t1_val t2_val
'2004-10-19 09:00:00' 1.23 null
'2004-10-19 10:03:00' 1.23 23
'2004-10-19 10:03:30' 1.23 null
'2004-10-19 10:05:00' 1.25 42
一点解释:
在09:00:00,我们知道table1的值为1.23。 table2中没有值,因此该值应该为null。
在10:03:00,table2增加了23。 table1中的值1.23仍然是table1中的最后一个已知值,因此它仍应存在于输出中。
10:03:30如上。
10:05:00 table1和table2都获得了新值,但查询只返回输出中的一行,包含t1_val和t2_val中的两个新值。
在请求的时间范围之前过滤掉可能的值实际上并不重要。如果table2的值设置为08:59:00,如果该值在示例的第一行的t2_val中显示,即使它不是最佳的,也没有坏处。
(请注意,我有大约30个表来组合数据,因此寻找可以扩展到许多表的解决方案。无法更改表格布局。不需要高性能。)
答案 0 :(得分:1)
我建议创建一个结合了所有数据的视图,然后根据需要查询视图。
创建视图:
create view combined_output as select * from table1 union all
select * from table2 union all
...
select * from tableN;
运行查询:
SELECT update_time, t1_val, t2_val
FROM combined_output
WHERE update_time between '2004-10-19 08:00:00' and '2004-10-19 12:00:00'
警告:我没有尝试过这些。
答案 1 :(得分:0)
如果表格与外键相关联,则可以使用连接语句来完成 从你的表中看起来没有FK所以使用联盟。但是,这将为您提供大量数据。
答案 2 :(得分:0)
我找到了一个将函数与select结合起来的解决方案。
首先,我创建一个函数,返回特定时间的已知值:
DROP FUNCTION last_known_values(timestamp without time zone,integer,text);
CREATE OR REPLACE FUNCTION public.last_known_values(
IN time_to_check timestamp without time zone,
IN id1 integer,
IN id2 text)
RETURNS TABLE(checked_time timestamp without time zone, id1 integer, id2 text, t1_val numeric, t2_val int) AS
$BODY$
SELECT time_to_check AS time, id1, id2,
(
SELECT table1.val AS t1_val from table1
WHERE $1 >= table1.update_time
AND table1.id1 = $2
AND table1.id2 = $3
ORDER BY table1.update_time DESC
LIMIT 1
),
(
SELECT table2.val AS t2_val from table2
WHERE $1 >= table2.update_time
AND table2.id1 = $2
AND table2.id2 = $3
ORDER BY table2.update_time DESC
LIMIT 1
)
$BODY$
LANGUAGE sql VOLATILE
COST 100
ROWS 1000;
然后我在任何时间戳范围内使用此函数,过滤所以只获取table1或table2(..tableN)中存在的时间戳:
SELECT last_known_values.* FROM (
SELECT DISTINCT update_time
FROM (
SELECT update_time
FROM table1
WHERE update_time BETWEEN '2004-10-19 08:00:00' AND '2004-10-19 12:00:00'
AND table1.id1 = 1
AND table1.id2 = 'ident 1'
UNION
SELECT update_time
FROM table2
WHERE update_time BETWEEN '2004-10-19 08:00:00' AND '2004-10-19 12:00:00'
AND table2.id1 = 1
AND table2.id2 = 'ident 1'
) t
ORDER BY update_time ASC
) times_to_fetch, last_known_values(times_to_fetch.update_time, 1, 'ident 1'::text);
给出结果:
"2004-10-19 09:00:00" 1 "ident 1" 1.23 (null)
"2004-10-19 10:03:00" 1 "ident 1" 1.23 23
"2004-10-19 10:03:30" 1 "ident 1" 1.23 (null)
"2004-10-19 10:05:00" 1 "ident 1" 1.25 42