在 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 网站的链接服务器

如何在 d3.js 中创建家谱?

SQL Server中创建Oracle的链接服务器

转SQL Server 数据库创建链接服务器访问另外一个SQL Server 数据库

在 SQL 中创建连接函数

sql server 和 mysql 之间的链接服务器上的分布式事务