同一个表上的传递SQL查询

时间:2010-04-05 11:12:00

标签: sql postgresql self-join

嘿。考虑下表和数据......

in_timestamp | out_timestamp | name  | in_id | out_id | in_server | out_server | status
timestamp1   | timestamp2    | data1 |id1   | id2    | others-server1   | my-server1 | success
timestamp2   | timestamp3    | data1 | id2   | id3    | my-server1   | my-server2 | success
timestamp3   | timestamp4    | data1 | id3   | id4    | my-server2   | my-server3 | success
timestamp4   | timestamp5    | data1 | id4   | id5    | my-server3   | others-server2 | success
  • 上述数据表示跨服务器的某些数据的执行流程的日志。
  • e.g。一些数据从一些'outside-server1'流向一堆'my-servers',最后流向'others-server2'。

问题:

1)我需要将这个可登录形式的日志提供给客户,在那里他不需要知道关于'my-servers'的一堆信息。我应该给出的是我的基础设施和离开时的数据的时间戳;深入了解以下信息。

in_timestamp (of 'others_server1' to 'my-server1')
out_timestamp (of 'my-server3' to 'others-server2')
name 
status

我想写同样的sql!有人可以帮忙吗? 注意:可能不会有3个'my-servers'。它因情况而异。例如例如,data2可能涉及4个“我的服务器”!

2)SQL还有其他替代方案吗?我的意思是存储过程/等?

3)优化? (记录数量巨大!到目前为止,每天大约有500万。我们应该显示长达一周的记录。)

事先,感谢帮助! :)

4 个答案:

答案 0 :(得分:2)

WITH RECURSIVE foo AS
        (
        SELECT  *, in_timestamp AS timestamp1, 1 AS hop, ARRAY[in_id] AS hops
        FROM    log_parsing.log_of_sent_mails
        WHERE   in_server = 'other-server1'
        UNION ALL
        SELECT  t_alias2.*, foo.timestamp1, foo.hop + 1, hops || in_id
        FROM    foo
        JOIN    log_parsing.log_of_sent_mails t_alias2
        ON      t_alias2.in_id = (foo.t_alias1).out_id 
        )
SELECT  *
FROM    foo
ORDER BY
        hop DESC
LIMIT 1

答案 1 :(得分:1)

你的桌子有一个层次结构(邻接列表)。这可以在PostgreSQL v8.4及更高版本中使用递归CTE有效查询。 Quassnoi撰写了一篇关于如何实施该文件的blog post。这是一个非常复杂的查询,您需要编写,但他用非常类似于您需要的示例解释它。特别是如果你看看他的最后一个例子,他演示了一个查询,而不是通过使用数组获得从第一个节点到最后一个节点的完整路径。

答案 2 :(得分:0)

这样做的一种方式 - 如果数据是稳定的(例如永远不会更改插入的on)是计算飞行中的传递关系(例如通过触发器或插入的应用程序) )在插入时间。

E.g。你的表中有一个新列“start_ts”;插入记录时:

in_timestamp | out_timestamp | name  | in_id | out_id | in_server | out_server | status
timestamp3   | timestamp4    | data1 | id3   | id4    | my-server2   | my-server3 | success

...然后您的逻辑会自动找到包含name=data1out_id=id3的记录,并将其start_ts克隆到新插入的记录中。您可能需要一些特殊的逻辑来传播最后的状态,具体取决于您如何计算这些传递值。

顺便说一句,您无需查询上一个(name=data1out_id=id3)记录 - 您可以在处理时将start_ts值保留在数据记录的元数据本身中。

然后最终的报告只是select start_ts, out_ts from T where out_server=others_server2(当然,就out_server和状态来说更复杂,但仍然是一个简单的选择)

第二个选项当然是更简单的循环计算结果报告 - 如果您不确定如何,对于SQL BFS实施,谷歌或“堆栈”(现在是一个可接受的动词?)

答案 3 :(得分:0)

  • @Other Readers:

    请参阅Mark Byers首先发布的第一个答案。我使用'回答'而不是'评论'他的帖子,因为我需要使用表格/链接等,这在评论答案时是不可用的。 :)

  • @Mark Byers:

感谢您的链接...它真的帮助了我,我能够找到在服务器之间生成路径的方法......看看@我能做什么。

in_id   | in_timestamp  | out_timestmap | name  | hops_count    | path  |
id1     | timestamp1    | timestamp2    | data1 | 1             | {id1} |
id2     | timestamp2    | timestamp3    | data1 | 2             | {id1,id2} |
id3     | timestamp3    | timestamp4    | data1 | 3             | {id1,id2,id3} |
id4     | timestamp4    | timestamp2    | data1 | 4             | {id1,id2,id3,id4} |

*路径是使用'in_id'生成的

我使用了以下查询...

WITH RECURSIVE foo AS
        (
        SELECT  t_alias1, 1 AS hops_count, ARRAY[in_id] AS hops
        FROM    log_parsing.log_of_sent_mails t_alias1
        WHERE   in_server = 'other-server1'
        UNION ALL
        SELECT  t_alias2, foo.hops_count + 1 AS hops_count, hops || in_id
        FROM    foo
        JOIN    log_parsing.log_of_sent_mails t_alias2
        ON      t_alias2.in_id = (foo.t_alias1).out_id 
        )
SELECT  (foo.t_alias1).in_id,
        (foo.t_alias1).name,
        (foo.t_alias1).in_timestamp,
        hops_count,
        hops::VARCHAR AS path
FROM    foo   ORDER BY   hops

但我还没达到最终阶段。这是我最终希望得到的......

in_id   | in_timestamp  | out_timestmap | name  | hops_count    | path  |
id4     | timestamp1    | timestamp5    | data1 | 4             | {id1,id2,id3,id4}|

*观察时间戳。它是必需的,因为我不希望客户知道内部基础设施。所以对他而言,时间戳1和时间戳5之间的时间延迟才是最重要的。

任何线索我怎么可能实现它!?

P.S。我也会尝试联系Quassnoi。 :)