这就是我想要做的。我有一张简单的表格:
table USAGE_LOG:
USAGE_ID
PC_ID
MEMORY_STICK_ID
因此,每个使用条目代表一个与特定记忆棒一起使用的PC。
PC和记忆棒ID都链接到设备表,其中device_type对于PC为1,对于记忆棒为2。
我的情况是我在某些PC上发现了病毒,现在我需要使用我的USAGE_LOG表跟踪所有可能受感染的机器。
我的电脑被标记为在另一张桌子中有病毒:
table VIRUS:
PC_ID
VIRUS_ID
我需要创建一个CTE(或视图),通过递归搜索连接到受感染PC的每个记忆棒来保存所有可能受感染设备的列表,然后我需要找到连接到每个可疑记忆棒的每台PC ,以及随后的每台PC等等。
限制是我无法更改我的数据结构,也无法创建任何函数或存储过程。
这是可能的,如果是这样,它是如何完成的?
答案 0 :(得分:1)
我为那些想要自己查看的人提供了我的测试设置:
CREATE TEMP TABLE usage_log (
usage_id int primary key
, pc_id int
, memory_stick_id int);
INSERT INTO usage_log VALUES
(1,1,2)
, (2,3,2)
, (3,3,4)
, (4,5,4)
, (5,5,6)
, (6,7,6)
, (7,9,8)
, (8,9,10)
, (9,3,12)
, (10,11,12)
, (11,11,13);
CREATE TEMP TABLE virus(
pc_id int
, virus_id int);
INSERT INTO virus values
(3, 4)
, (3, 5)
, (5, 6)
/* Alternative test:
TRUNCATE VIRUS;
INSERT INTO virus values
(9, 4)
, (9, 5);
*/
此查询应该会递归地查找可能被内部使用感染的所有PC和USB记忆棒:
WITH RECURSIVE v_start AS (
SELECT pc_id, max(u.usage_id) AS usage_id
FROM virus v
JOIN usage_log u USING (pc_id)
GROUP BY 1
),
v_down AS (
SELECT u.*
FROM usage_log u
JOIN v_start v USING (usage_id)
UNION
SELECT DISTINCT u.*
FROM usage_log u
JOIN v_down v ON u.pc_id = v.pc_id OR u.memory_stick_id = v.memory_stick_id
WHERE u.usage_id < v.usage_id
),
v_up AS (
SELECT u.*
FROM usage_log u
JOIN v_down v USING (usage_id)
UNION
SELECT DISTINCT u.*
FROM usage_log u
JOIN v_up v ON u.pc_id = v.pc_id OR u.memory_stick_id = v.memory_stick_id
WHERE u.usage_id > v.usage_id
)
SELECT pc_id, 1 AS device_type -- PCs
FROM v_up
GROUP BY 1
UNION ALL
SELECT memory_stick_id, 2 AS device_type -- USB-sticks
FROM v_up
GROUP BY 1
ORDER BY 2, 1
我认为usage_id
是反映时间表的连续列。
编辑 v_start
我找到了每个受感染PC的最新日志条目。完全忽略了这种病毒。在我的第一个版本中,我有最早的使用min(usage_id)
,但那是在我改进查询以包含所有前体之前,然后然后让它沿着时间轴传播。我们现在必须从最新的使用开始,其中包括更多的嫌疑人。如果我们有更多信息可以使用,我们可以缩小搜索范围。
第一个CTE也是RECURSIVE
,因为从技术上讲,您一次只能使用一种CTE。没有UNION
部分,它实际上是普通CTE 。有关WITH clause (CTE)。
在以下两个CTE中,我按时返回工作,然后再转发以查找可能已联系的任何USB-stick 或 PC。 时间顺序是相关的。请参阅以下说明
请注意,我在初稿中使用 UNION
代替UNION ALL
。每一步消除重复都应该更有效。
最终SELECT
是一个穷人的数据透视表功能,同时删除PC和USB记忆棒之间的任何重复项。在这种情况下,两个列表都与UNION ALL
放在一起。最终结果按设备类型和设备ID排序。
最糟糕的情况是我们必须假设的,这意味着在任何使用期间,PC可能已被感染。
我们需要从最新用途中强化返回(v_down
),以包含病毒可能来自的所有设备。
然后,从所有可疑行开始,我们再次将前进(v_up
)延长,找到可能已被感染的任何和所有设备。
Voilá:可能涉及的所有PC和USB记忆棒。
考虑这个设置:
INSERT INTO usage_log VALUES
(1,1,2) -- PC 1 connects to stick 3
, (3,3,4) -- PC 3 connects to stick 4
, (2,3,2) -- PC 3 connects to stick 2
, (2,3,6); -- PC 3 connects to stick 6
在这里,坚持4 从不与USB 2,代理或不接触。但如果我们忽略时间表,他们就会联系起来。 Stick 6通过代理连接到Stick 2,因为它连接到PC 3 后它与Stick 2联系。