获取具有匹配子记录的2个表之间的ID对

时间:2013-06-09 11:43:34

标签: sql sql-server

我有2张具有相同结构的表。

FIELD 1      INT
FIELD 2      VARCHAR(32)   -- is a MD5 Hash

对于在表1和表2中具有FIELD 2的值的精确组合的记录,查询必须获得匹配的FIELD 1对。

这些表非常大(两者之间有100万条记录),但推断为ID和哈希。

示例数据:

表1

1     A
1     B
2     A
2     D
2     E
3     G
3     H
4     E
4     D
4     C
5     E
5     D

表2

8     A
8     B
9     E
9     D
9     C
10    F
11    G
11    H
12    B
12    D
13    A
13    B
14    E
14    A
查询的结果应该是
8     1
9     4
11    3
13    1

我尝试使用相关的子查询和我在这里阅读的FOR XML PATH字符串技巧创建FIELD 2的连接字符串,但这非常慢。

2 个答案:

答案 0 :(得分:1)

您也可以尝试以下查询 -

SELECT t_2.Field_1, t_1.Field_1                          --1
  FROM table_1 t_1, table_2 t_2                          --2
 WHERE t_1.Field_2 = t_2.Field_2                         --3
 GROUP BY t_1.Field_1, t_2.Field_1                       --4
HAVING COUNT(*) = (SELECT COUNT(*)                       --5
                     FROM Table_1 t_1_1                  --6
                    WHERE t_1_1.Field_1 = t_1.Field_1)   --7
   AND COUNT(*) = (SELECT COUNT(*)                       --8
                     FROM Table_2 t_2_1                  --9
                    WHERE t_2_1.Field_1 =t_2.Field_1)    --10

修改

首先,请求的结果集是来自两个表的Field1的组合,其中各个Field2完全相同。

所以你可以使用我上面发布的一种方法。

下面 查询将根据field2值(从第1行到第3行)从表中获取数据 然后它将基于table1的field1和table2的第1行(第4行)

对数据进行分组

直到这一步,你将获得结果,其中table1来自table1,field2来自table2,其中存在(至少一个)匹配基于相应field1值的表中的field2。

在此之后,您只需要过滤结果的正确性(对于相应的field1列值,field2值的值完全相同)。这样你就可以计算行数。

  

这里我的假设是在表

中没有field1和field2组合的多个值

表示以下行不会出现 -

1 b 1 b

在任何表格中。

如果是这样,table1和table2的行计数得到的相同field2值应该与table1中为field1存在的行匹配,并且相同的行只应出现在tables2中为field2值。

对于此条件,查询在count(*)子句中的having具有条件(从第5行到第10行)。

答案 1 :(得分:0)

让我试着解释这个版本的查询:

select t1.field1 as t1field1, t2.field1 as t2field1
from (select t1.*,
             count(*) over (partition by field1) as NumField2
      from table1 t1
     ) t1 full outer join
     (select t2.*,
             count(*) over (partition by field1) as NumField2
      from table2 t2
     ) t2
     on t1.field2 = t2.field2
where t1.NumField2 = t2.NumField2
group by t1.Field1, t2.Field1
having count(t1.field2) = max(t1.NumField2) and
       count(t2.field2) = max(t2.NumField2)

(在SQLFiddle中为here)。

我们的想法是比较每对field1值的以下计数。

  1. 每个field2值的数量。
  2. 他们共享的field2值的数量。
  3. 所有这些必须是平等的。

    每个子查询计算每个field2值上field1的值的数量。对于数据的第一行,这会产生:

    1    A    2
    1    B    2
    2    A    3
    2    D    3
    2    E    3
    . . .
    

    对于第二张表

    8    A    2
    8    B    2
    9    E    3
    9    D    3
    9    C    3
    

    接下来,应用full outer join,要求计数和field2值匹配。这会将数据相乘,产生如下行:

    1    A    2    8    A    2
    1    B    2    8    B    2
    2    A    3    NULL NULL NULL
    2    D    3    9    D    3
    2    E    3    9    E    3
    NULL NULL NULL 9    C    3
    

    等等所有可能的组合。请注意,NULL由于full outer join而显示。

    请注意,当您有一对(例如1和8)匹配时,没有值为NULL的行。如果您的一对具有相同的计数但它们不匹配,那么您有NULL个值。当您有一对具有不同计数的对时,它们会被where子句过滤掉。

    过滤聚合步骤应用这些规则来获得满足第一个条件而不是第二个条件的对。

    having基本上会移除任何具有NULL值的对。当您count()列时,不会包含NULL个值。在这种情况下,列上的count()少于预期值NumField2)。