Sql 将表结果合并到列中

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

(这是对的后续问题)

我有大约30个表,从外部系统获取“流式”数据。我试图找出如何将收集到的数据合并到单个查询结果中

让我们描述一下表格布局:

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会将所有值放在同一列中。我正在寻找某种方法将不同的表合并到单独的列中,但将“最后的已知值”合并到一行中。如上所述,联合将不同表中的数据合并到一个列中,而不是按要求分开。