【问题标题】:SQL - identifying exact matches across multiple recordsSQL - 识别多条记录的完全匹配
【发布时间】:2009-05-18 23:07:05
【问题描述】:

父表

Column1
S1
S2
S3

表子

Column1     Column2
S1          P1
S1          P2
S2          P1
S2          P2
S3          P1

其中 parent.column1 = child.column1

鉴于上述表格,我需要确定其孩子在 column2 中的记录与父 S1 相同的父母。

例如,S1 和 S2 都有 P1 和 P2,这样就满足条件。然而,S3 没有 P2,因此应该被排除在外。

SQL 新手,所以我遇到了一些麻烦。尝试使用 not in 语句,但由于 S3 有 P1,因此不会被排除。

【问题讨论】:

  • 您是在寻找所有与 S1 拥有相同孩子的父母,还是寻找任何拥有相同孩子的父母?

标签: sql ms-access


【解决方案1】:

您需要加入。这将因 SQL 方言而异。比如:

select child.column1, child.column2 from (
  select column2 as parentsColumn2Value from child where column1='S1'
) as parentsColumn2Table
left join child on parentsColumn2Table.column2=child.column2

【讨论】:

    【解决方案2】:

    为找到所有匹配的父母的一般情况解决这个问题更有趣:) 请参阅底部的注释,了解如何将其用于更简单的情况(其中一个父键是固定的)。

    我会给出我认为“合适”的解决方案,但我没有 Access(或 SQL Server)的副本可供查看它是否可以在其中工作。 (是的,我已经在这里针对数据库进行了测试......)

    SELECT p1.column1, p2.column1
    FROM parent p1 JOIN parent p2 ON p1.column1 < p2.column1
    WHERE NOT EXISTS (SELECT 1
           FROM (SELECT c1.column1, c1.column2 FROM child c1 WHERE c1.column1 = p1.column1) c1f
                FULL OUTER JOIN
                (SELECT c2.column1, c2.column2 FROM child c2 WHERE c2.column1 = p2.column1) c2f
                ON c1f.column2 = c2f.column2
           WHERE c1f.column1 IS NULL OR c2f.column1 IS NULL
          );
    

    所以希望你能看到我上面所说的内容是如何联系在一起的 :) 我会试着解释一下......

    “外部”(第一个)选择生成 column1 值的组合(p1.column1 和 p2.column1)。对于每个组合,我们在“child”中列出这些值的行(这些是 c1f 和 c2f:c1f 表示“child 1 filtered”)并执行 FULL OUTER JOIN。根据我的经验,这是一个相对罕见的结构。我们想要匹配 所有 c1f 和 c2f 中的条目(使用它们的 column1 值),并找到任何 任一侧 没有对应条目的另一侧边。如果有任何这样的非匹配器,那么它们将显示为来自连接的行,其 column1 值为空。因此,父查询仅选择子查询中不存在此类行的 column1 值的组合,即 p1 的 column1 值的每个子行都有一个对应于 p2 的 column1 值的子行,反之亦然。

    例如,对于 p1.column1 为“S1”且 p2.column2 为“S3”的迭代,该子查询(没有聚合)将产生:

     c1f__column1 | c1f__column2 | c2f__column1 | c2f__column2
    --------------+--------------+--------------+--------------
     S1           | P1           | S3           | P1
     S1           | P2           |              |
    

    并且正是第二行中的那些空值将该组合标记为不匹配。涉及到一些曲折的想法,当找到不匹配的组合更容易时,很容易专注于寻找匹配的组合。

    作为最后的奖励,当我为此创建一些测试表时,我将 (column1,column2) 设置为 child 的主键,这恰好是驱动过滤表的完全外连接所需要的有效率的。赢! (所以请注意,我没有尝试处理 child 中的重复组合......但你可以在 c1f 和 c2f 派生中打“distinct”)

    NB 基于 Matt 的评论,如果您的父值之一是已知的(即您只想列出与 S1 具有相同子项的所有父值),那么您只需拍打“and p1.column1 = 'S1'”最后。但是在这种情况下,将“parent p1 JOIN parent p2 ON p1.column1

    【讨论】:

      【解决方案3】:

      这是一个 Access,而不是 SQL 解决方案,因为它使用了用户定义函数 (UDF)。

      SELECT p.Column1, 
             ConcatList("SELECT Column2 FROM c WHERE Column1='S1'","|") AS S1, 
             ConcatList("SELECT Column2 FROM c WHERE Column1='" & [p].[Column1] & "'","|") AS Child, 
             Format([S1]=[Child],"Yes/No") AS [Match]
      FROM p;
      

      UDF

         Function ConcatList(strSQL As String, strDelim, ParamArray NameList() As Variant)
         ''Reference: Microsoft DAO x.x Object Library
         Dim db As Database
         Dim rs As DAO.Recordset
         Dim strList As String
      
         Set db = CurrentDb
      
         If strSQL <> "" Then
             Set rs = db.OpenRecordset(strSQL)
      
             Do While Not rs.EOF
                 strList = strList & strDelim & rs.Fields(0)
                 rs.MoveNext
             Loop
      
             strList = Mid(strList, Len(strDelim) + 1)
         Else
      
             strList = Join(NameList, strDelim)
         End If
      
         ConcatList = strList
      
         End Function
      

      很遗憾,我认为 Jet 不支持 Full Outer Join,因此仅使用 SQL 的解决方案可能有点繁琐,并且需要更多信息,例如 S1 在 column2 中是否有固定数量的条目。

      【讨论】:

      • Access 支持完全外部联接,如果您使用支持它的后端。 ;)
      • 你不能让我明白,这次我说的是 Jet! :D
      【解决方案4】:

      ACE/Jet 可能不直接支持 FULL OUTER JOIN,但解决方法很简单,即分别将表的所有 LEFT JOIN、INNER JOIN 和 RIGHT JOIN 联合起来。

      【讨论】:

        【解决方案5】:

        顺便说一句,我正在寻找相同的解决方案并自己想通了

        select * from TableParent where id in 
          (select temp_parent.id from
            (select TableParent.*, count(exact_match.match_count) as exact_count 
             from TableParent
             inner join 
               (select Column1, count(*) as match_count from TableChild
                group by Column1
                having match_count = 2
               ) as exact_match on exact_match.Column1 = TableParent.Column1
             inner join 
               TableChild on TableChild.event_id = exact_match.Column1 where TableChild.Column2 in (P1,P2)
           group by TableParent.Column1
           having exact_count = 2) as temp_parent)
        

        【讨论】:

          猜你喜欢
          • 2012-12-13
          • 2015-05-02
          • 1970-01-01
          • 1970-01-01
          • 2019-01-24
          • 1970-01-01
          • 1970-01-01
          • 2021-01-31
          • 2021-09-08
          相关资源
          最近更新 更多