我有my_table t
id in_node out_node weight
1 'A' 'B' 17
2 'B' 'A' 4
3 'C' 'A' 35
4 'A' 'D' 26
...
5 'C' 'G' 33
6 'X' 'Z' 12
7 'Z' 'Y' 15
8 'X' 'Y' 42
9 'K' 'M' 66
...
10 'A' 'Z' 20
期望的行为
select id, in_count, in_weight, out_count,out_weight from t where id = 10
10 3 65 2 27
2,3,4 4+35+26 6,7 12+15
(1 is duplicate)
计算不同in_neighbors数量的步骤:
$A: select in_node from t where id = 10
@B: select id from t where in_node = $A or out_node = $A --select in neighbor ids (1,2,3,4,10)
@C: select in_node as that_node from t where id in (@B) -- ('A', 'B', 'C') union all select out_node as that_node from t where id in (@B) --('A','B','Z','D')
(count distinct @C) --5 now we can subtract two ('A' and 'Z' nods) to get the number of neighbors from in_node side
要计算in_weight,我们应该从t在(2,3,4)中的id中选择sum(weight)。我们不应该为id = 1计算重量,因为
select in_node from t where id = 1
union all
select out_node from t where id = 1
--'A','B'
产生与
相同的集合select in_node from t where id = 2
union all
select out_node from t where id = 2
--'A','B'
同时
select weight from t where id = 2
小于
select weight from t where id = 1
是否可以从Oracle PL SQL中进行这种选择,还是仅将结果集传递给Java更容易?
此表代表图形。顶点为in_node
和out_node
,id
对应于边缘,weight
对应于边缘的权重。我想找到所有相邻的边缘及其权重。如果有多个连接两个顶点的边,则仅应考虑最浅的边。
因此,“ in_total”对应于“不同的”相邻边缘的权重的总和。 “截然不同”是指连接两个给定顶点的最亮边。
我正在模拟整个图形的最大移动距离。有时会多次报告A-B路线。在这种情况下,我只想选择一条重量最轻的A-B路线。
邻居总数超过邻居总数是解决我的问题的有用指标。
答案 0 :(得分:2)
这可以使用分层查询来获取相邻节点,然后进行相应的求和:
WITH t AS (SELECT 1 ID, 'A' in_node, 'B' out_node, 17 weight FROM dual UNION ALL
SELECT 2 ID, 'B' in_node, 'A' out_node, 4 weight FROM dual UNION ALL
SELECT 3 ID, 'C' in_node, 'A' out_node, 5 weight FROM dual UNION ALL
SELECT 4 ID, 'A' in_node, 'D' out_node, 6 weight FROM dual UNION ALL
SELECT 5 ID, 'C' in_node, 'G' out_node, 33 weight FROM dual UNION ALL
SELECT 6 ID, 'X' in_node, 'Z' out_node, 12 weight FROM dual UNION ALL
SELECT 7 ID, 'Z' in_node, 'Y' out_node, 15 weight FROM dual UNION ALL
SELECT 8 ID, 'X' in_node, 'Y' out_node, 42 weight FROM dual UNION ALL
SELECT 9 ID, 'K' in_node, 'M' out_node, 66 weight FROM dual UNION ALL
SELECT 10 ID, 'A' in_node, 'Z' out_node, 20 weight FROM dual),
res AS (SELECT ID,
in_node,
out_node,
weight,
MAX(CASE WHEN ID = connect_by_root(ID) THEN in_node END) OVER () orig_in_node,
MAX(CASE WHEN ID = connect_by_root(ID) THEN out_node END) OVER () orig_out_node,
MAX(CASE WHEN ID = connect_by_root(ID) THEN ID END) OVER () orig_id,
CASE WHEN MAX(CASE WHEN ID = connect_by_root(ID) THEN in_node END) OVER () IN (in_node, out_node) THEN 'in'
ELSE 'out'
END direction_from_orig_node,
LEAST(in_node, out_node) node1,
GREATEST(in_node, out_node) node2,
row_number() OVER (PARTITION BY LEAST(in_node, out_node), GREATEST(in_node, out_node) ORDER BY weight) rn
FROM t
START WITH ID = 10
CONNECT BY NOCYCLE (PRIOR out_node IN (in_node, out_node)
OR PRIOR in_node IN (in_node, out_node))
AND LEVEL <= 2)
SELECT orig_id,
COUNT(DISTINCT CASE WHEN direction_from_orig_node = 'in' THEN node1||'~'||node2 END) in_count,
nvl(SUM(CASE WHEN direction_from_orig_node = 'in' THEN weight END), 0) in_sum,
COUNT(DISTINCT CASE WHEN direction_from_orig_node = 'out' THEN node1||'~'||node2 END) out_count,
nvl(SUM(CASE WHEN direction_from_orig_node = 'out' THEN weight END), 0) out_sum
FROM res
WHERE rn = 1
AND ID != orig_id
GROUP BY orig_id;
给出:
ORIG_ID IN_COUNT IN_SUM OUT_COUNT OUT_SUM
---------- ---------- ---------- ---------- ----------
10 3 15 2 27
如果起始ID = 5,则得到:
ORIG_ID IN_COUNT IN_SUM OUT_COUNT OUT_SUM
---------- ---------- ---------- ---------- ----------
5 1 5 0 0