在 SQL 中创建数据之间的链接
Posted
技术标签:
【中文标题】在 SQL 中创建数据之间的链接【英文标题】:Create link between data in SQL 【发布时间】:2020-09-15 19:56:22 【问题描述】:我有以下数据:
Source Target
A1 B1
A2 B1
A3 B1
A1 B2
A2 B2
A3 B2
A1 B3
A2 B3
A3 B3
A1 B4
A2 B4
基本上,这意味着 B1、B2 和 B3 依赖于 A1、A2 和 A3。 B4 仅取决于 A1、A2。 我将这些数据导出到图表中,以绘制数据之间的关系并具有更易于分析的可视化表示。你可以猜到,这会产生很多线条,而且图表并不是很清晰。 我想通过创建中间数据 (Cx) 来重新组合它们:对于与另一个目标具有相同源的每个目标,都会创建 Cx。 这会给:
A1 C1
A2 C1
A3 C1
C1 B1
C1 B1
C1 B1
A1 C2
A2 C2
C2 B4
这样,在图表中,A1、A2 和 A3 将链接到 C1,而 C1 将链接到 B1、B2、B3。 A1 和 A2 将链接到 C2,C2 将链接到 B4 这样可以避免线相互交叉。
我尝试使用 listagg 创建 Cx,但没有成功。
有什么想法吗?
【问题讨论】:
【参考方案1】:您可以创建一个集合:
CREATE TYPE item_list AS TABLE OF CHAR(2);
然后使用它聚合一次以整理源,然后再次聚合以整理目标并分配链接值,然后您可以解包聚合值:
WITH links ( sources, targets, link ) AS (
SELECT sources,
targets,
'C' || ROWNUM
FROM (
SELECT sources,
CAST( COLLECT( target ) AS item_list ) AS targets
FROM (
SELECT LISTAGG( source, ',' ) WITHIN GROUP ( ORDER BY source ) AS sources,
target
FROM table_name
GROUP BY target
)
GROUP BY sources
)
)
SELECT l.link AS source,
t.COLUMN_VALUE AS target
FROM links l
CROSS JOIN TABLE( l.targets ) t
UNION ALL
SELECT s.COLUMN_VALUE,
l.link
FROM links l
CROSS JOIN TABLE(
CAST(
MULTISET(
SELECT REGEXP_SUBSTR( l.sources, '[^,]+', 1, LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( l.sources, '[^,]+' )
)
AS item_list
)
) s
(注意:尝试 GROUP BY
包含集合数据类型的列会引发异常,因此为避免这种情况,第一阶段的聚合是使用 LISTAGG
完成的,然后在一个表集合表达式。将CAST
/COLLECT
用于两个聚合会更简单,但这似乎是不可能的。)
其中,对于您的示例数据:
CREATE TABLE table_name ( source, target ) AS
SELECT 'A1', 'B1' FROM DUAL UNION ALL
SELECT 'A2', 'B1' FROM DUAL UNION ALL
SELECT 'A3', 'B1' FROM DUAL UNION ALL
SELECT 'A1', 'B2' FROM DUAL UNION ALL
SELECT 'A2', 'B2' FROM DUAL UNION ALL
SELECT 'A3', 'B2' FROM DUAL UNION ALL
SELECT 'A1', 'B3' FROM DUAL UNION ALL
SELECT 'A2', 'B3' FROM DUAL UNION ALL
SELECT 'A3', 'B3' FROM DUAL UNION ALL
SELECT 'A1', 'B4' FROM DUAL UNION ALL
SELECT 'A2', 'B4' FROM DUAL;
输出:
来源 |目标 :----- | :----- C1 | B4 C2 | B1 C2 | B3 C2 | B2 A1 | C1 A2 | C1 A1 | C2 A2 | C2 A3 | C2
db小提琴here
【讨论】:
【参考方案2】:您可以使用以下方法获取共享所有相同来源的目标值:
select sources, target,
dense_rank() over (order by sources) as c_number
from (select target, listagg(source, ',') within group (order by source) as sources
from t
group by target
) t;
我不确定这是否足以满足您的要求。这提供了分组。
【讨论】:
这给出了 C1 和 B1/B2/B3 之间以及 C2 和 B4 之间的链接。现在我需要调整它以在 A1/A2/A3 和 C1 之间以及 A1/A2 和 C2 之间建立链接 这似乎有效。明天我会检查: select 'TARGET',sources, target, dense_rank() over (order by sources) as c_number from (select target, listagg(source, ',') within group (order by source) as sources from datas group by target ) union select 'SOURCE',sources, source, dense_rank() over (order by sources) as c_number from (select source, listagg(source, ',') inside group (order by source) over (partition by target ) 作为数据源)以上是关于在 SQL 中创建数据之间的链接的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SQL Server 2014 中创建指向 SharePoint 网站的链接服务器