【问题标题】:Select records without duplicate with specific logic使用特定逻辑选择不重复的记录
【发布时间】:2021-10-07 13:28:22
【问题描述】:

我有一张表 ABC,其中包含很多列 (30+)。所有的主要列是IdRefNumber

我还有表 LinkedEntity 可以匹配来自不同表的记录(ABC

我需要从表 A 中选择所有记录并显示来自 BC 的链接记录

一个

Id RefNumber OtherColumns
101 A101 ...
102 A102 ...

B

Id RefNumber OtherColumns
201 B101 ...
202 B102 ...

C

Id RefNumber OtherColumns
301 C101 ...
302 C102 ...

关联实体

Id EntityId LinkedEntityId
1 101 202
2 102 301
3 102 201
4 102 202

预期结果:

Id RefNumber LinkedB LinkedBRefNumb LinkedC LinkedCRefNumb
101 A101 202 B102 NULL NULL
102 A102 201,202 B101,B102 301 C101

第一个想法写类似的东西

SELECT A.Id, A.RefNumber, L1.Id, L1.RefNumber, L2.Id, L2.RefNumber
FROM A
LEFT JOIN (SELECT B.Id, B.RefNumber, le.EntityId, le.LinkedEntityId FROM B JOIN LinkedEntity le ON le.EntityId = B.Id OR le.LinkedEntityId = B.Id) L1
ON A.Id = L1.EntityId OR A.Id = L1.LinkedEntityId 
LEFT JOIN (SELECT C.Id, C.RefNumber, le.EntityId, le.LinkedEntityId FROM C JOIN LinkedEntity le ON le.EntityId = C.Id OR le.LinkedEntityId = C.Id) L2
ON A.Id = L2.EntityId OR A.Id = L2.LinkedEntityId

但此查询返回 A 表的重复记录。 有什么方法可以删除重复项并加入linkedEntities 的值? (也许使用STRING_AGG)?

【问题讨论】:

  • STRING_AGG 会起作用,但您将要编写 很多STRING_AGG 表达式; 1 代表表 BC 中的每一列
  • 鉴于您的示例数据,我不明白 thise 连接是如何工作的。第 2 行的 LinkedB 是如何变成 102 的,为什么不是 LinkedBRefNumb B101, B102LinkedC如何加入?
  • @Charlieface 抱歉,我的错……添加了额外的单元格……已修复
  • 嗯 - 似乎您在表之间人为地划分(或假设)ID 值,使得 ID 201(作为示例)仅存在于一个表中。你确定这个假设永远不会被违反吗?让我们补充一下 - 为什么不使用常规交集表?
  • @SM 或者是的,我确信 id 会有所不同(在实时数据库中它更复杂......有额外的标志来确保 id 是我需要的)......你在常规下是什么意思路口?

标签: sql sql-server


【解决方案1】:

这是一种使用连接的简单方法,我在 LinkedEntity 中使用一些额外的重复条目进行了测试(您当前的设计允许这样做,您可以使用 EntityId 和 LinkedEntityId 的复合键来解决此问题,并从该表中删除 Id)。

对于旧版本的 sql server,您确实需要使用 STRING_AGGone of these other approaches 对记录进行分组。此外,如果您有兴趣对分组的连接数据进行排序,docs 提供了如何排序数据的其他示例。

这使用IN 运算符和左连接来检索链接的实体,并使用 distinct 关键字来删除重复项。

查询 1

SELECT
    AId as Id,
    ARefNumber as RefNumber,
    STRING_AGG(BId,',') as LinkedB,
    STRING_AGG(BRefNumber,',') as LinkedBRefNumb,
    STRING_AGG(CId,',') as LinkedC,
    STRING_AGG(CRefNumber,',') as LinkedCRefNumb
FROM (
    SELECT DISTINCT
        A.Id as AId,
        A.RefNumber as ARefNumber,
        B.Id as BId,
        B.RefNumber as BRefNumber,
        C.Id as CId,
        C.RefNumber as CRefNumber
    FROM 
        A
    LEFT JOIN
        LinkedEntity le ON A.Id IN (le.EntityId,le.LinkedEntityId)
    LEFT JOIN
        B ON B.Id IN  (le.EntityId,le.LinkedEntityId) 
    LEFT JOIN
        C ON C.Id IN  (le.EntityId,le.LinkedEntityId) 
) t
GROUP BY
    AId,
    ARefNumber
Id RefNumber LinkedB LinkedBRefNumb LinkedC LinkedCRefNumb
101 A101 202 B102 null null
102 A102 201,202 B101,B102 301 C101

View working demo db fiddle

让我知道这是否适合你。

【讨论】:

    【解决方案2】:

    您是否尝试过外键(据我所知,我不确定该表是通过 id 还是 refnumber 链接的):

    ALTER TABLE A
       ADD CONSTRAINT Foreign1 FOREIGN KEY (Id)
          REFERENCES B (Id)
          ON DELETE RESTRICT
          ON DELETE RESTRICT
    

    从 b 到 c 以及从 Linkedentity 到 a、b、c 以此类推。这里是ms官方页面https://docs.microsoft.com/it-it/sql/relational-databases/tables/create-foreign-key-relationships?view=sql-server-ver15

    那么你所要做的应该是:

    SELECT * FROM A JOIN B JOIN C JOIN LinkedEntity
    

    【讨论】:

    • NATURAL JOIN 在 SQL Server 中无效??这如何回答这个问题?
    • 对不起,你是对的,我编辑并删除了自然。为什么不接听?
    【解决方案3】:
    SELECT
    a_id,
    a_RefNumber,
    GROUP_AGGR(b_id) AS b_aggr_id,
    GROUP_AGGR(b_RefNumber) AS b_aggr_ref,
    GROUP_AGGR(c_id) as c_aggr,
    GROUP_AGGR(c_RefNumber) AS c_aggr_ref
    FROM (
    
        SELECT
        A.id AS a_id,
        A.RefNumber AS a_RefNumber,
        B.id AS b_id,
        B.RefNumber AS b_RefNumber,
        NULL AS c_id,
        NULL AS c_RefNumber
        FROM A
        LEFT JOIN LinkedEntity X ON X.EntityId=A.id
        LEFT JOIN B ON X.LinkedEntityId=B.id
    
        UNION ALL
    
        SELECT
        A.id AS a_id,
        A.RefNumber AS a_RefNumber,
        NULL AS b_id,
        NULL AS b_RefNumber,
        C.id AS c_id,
        C.RefNumber AS c_RefNumber
        FROM A
        LEFT JOIN LinkedEntity X ON X.EntityId=A.id
        LEFT JOIN C ON X.LinkedEntityId=C.id
    
    ) AS matrix
    GROUP BY a_id, a_RefNumber
    ORDER BY 1
    

    【讨论】:

    • GROUP_AGGR 不是 SQL Server 中的内置函数。如果你想使用它,你需要包含它的定义。
    猜你喜欢
    • 1970-01-01
    • 2021-05-16
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多