Sql 将表结果合并到列中
(这是对的后续问题) 我有大约30个表,从外部系统获取“流式”数据。我试图找出如何将收集到的数据合并到单个查询结果中 让我们描述一下表格布局:Sql 将表结果合并到列中,sql,postgresql,Sql,Postgresql,(这是对的后续问题) 我有大约30个表,从外部系统获取“流式”数据。我试图找出如何将收集到的数据合并到单个查询结果中 让我们描述一下表格布局: CREATE TABLE IF NOT EXISTS table1 ( id1 INT NOT NULL, id2 TEXT NOT NULL, update_time TIMESTAMP(6) NOT NULL, val NUMERIC NU
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
"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
一点解释:
在09:00:00,我们知道表1的值为1.23。表2中不存在值,因此该表中的值应为null
10:03:00时,表2添加了23。表1中的值1.23仍然是表1中最后一个已知的值,因此输出中仍应存在该值
10:03:30同上
10:05:00 table1和table2都获得了新值,但查询只返回输出中的一行,其中包含t1_val和t2_val中的两个新值
实际上,在请求的时间范围之前过滤掉可能的值并不重要。如果表2的值设置为08:59:00,那么如果该值在示例中第一行的t2_val中显示,即使不是最佳值,也没有什么坏处
(请注意,我有大约30个表可用于组合数据,因此正在寻找一种可以扩展到多个表的解决方案。不可能更改表布局。不需要高性能。)我建议创建一个组合所有数据的视图,然后您可以根据需要查询该视图 创建视图:
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'
警告:我没有尝试过任何方法。如果表是用外键链接的,可以用join语句来完成。
从表中的外观来看,没有FK,因此请使用并集。不过,这将为您提供大量数据。我找到了一种将函数与选择相结合的解决方案 首先,我创建一个函数,返回特定时间的已知值:
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;
然后,我将此函数用于任何时间戳范围,进行过滤,以便只提取表1或表2(…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);
给出了结果:
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
"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
您可以使用
full join
,但是查询太多表时会显得笨拙。使用union会将所有值放在同一列中。我正在寻找某种方法将不同的表合并到单独的列中,但将“最后的已知值”合并到一行中。如上所述,联合将不同表中的数据合并到一个列中,而不是按要求分开。