4

我有 2 个简单的表,我想用它们执行 INNER JOIN,但问题是我得到了重复的(对于列 str1 和 str2)结果:

CREATE TABLE #A (Id INT, str1 nvarchar(50), str2 nvarchar(50))
insert into #A  values (1, 'a', 'b')
insert into #A  values (2, 'a', 'b')

CREATE TABLE #B (Id INT, str1 nvarchar(50), str2 nvarchar(50))
insert into #B values (7, 'a', 'b')
insert into #B  values (8, 'a', 'b')

select * from #A a
INNER JOIN #B b ON a.str1 = b.str1 AND a.str2 = b.str2  

当我真的想要 2 条记录时,它给了我 4 条记录。

我得到了什么:
id | str1 | str2| 编号 | str1 | str2
1 | 一个 | 乙 | 7 | 一个 | 2
| 一个 | 乙 | 7 | 一个 | 1
| 一个 | 乙 | 8 | 一个 | 2
| 一个 | 乙 | 8 | 一个 | b

我真正想要的:
1个| 乙 | 7 | 一个 | b
2 一个 | 乙 | 8 | 一个 | b

任何人都可以帮忙吗?我知道这可以使用游标和循环来实现,但我想避免它,并且尽可能只使用某种类型的 JOIN。

4

3 回答 3

5
SELECT 
    a.id AS a_id, a.str1 AS a_str1, a.str2 AS a_str2, 
    b.id AS b_id, b.str1 AS b_str1, b.str2 AS b_str2
FROM 
    ( SELECT *
           , ROW_NUMBER() OVER (PARTITION BY str1, str2 ORDER BY id) AS rn
      FROM #A 
    ) a
  INNER JOIN 
    ( SELECT *
           , ROW_NUMBER() OVER (PARTITION BY str1, str2 ORDER BY id) AS rn
      FROM #B 
    ) b 
    ON  a.str1 = b.str1 
    AND a.str2 = b.str2 
    AND a.rn = b.rn ;

如果您在同一组合的一个或其他表中有更多行,您可以通过将join更改为或join(str1, str2)来选择将返回哪些行。INNERLEFTRIGHTFULL

于 2012-11-23T20:00:26.520 回答
3

可以使用如下查询(SQL 2005 及更高版本)完成某种匹配:

WITH A AS (
   SELECT
      Seq = Row_Number() OVER (PARTITION BY Str1, Str2 ORDER BY Id),
      *
   FROM #A
), B AS (
   SELECT
      Seq = Row_Number() OVER (PARTITION BY Str1, Str2 ORDER BY Id),
      *
   FROM #B
)
SELECT
   A.Id, A.Str1, A.Str2, B.Id, B.Str1, B.Str2
FROM
   A
   FULL JOIN B
      ON A.Seq = B.Seq AND A.Str1 = B.Str1 AND A.Str2 = B.Str2;

这将 A 和 B 之间的项目连接到其 Id-ordered 位置。但请注意:如果每组 Str1 和 Str2 的项目数不相等,则可能会得到意想不到的结果,因为 #A 或 #B 会出现 NULL。

我在这里假设您希望表#A 的“Str1 Str2”的第一行,按照#A.Id 的顺序(1 是第一个),与表#B 的“Str1 Str2”的第一行相关,按照顺序通过#B.Id (7 是第一个),依此类推,依次为每个连续编号的行。那正确吗?

但是如果行数不匹配,例如,#A 中有 3 行与 #B 中的 2 行具有相同的值,你会怎么做?还是反过来?你要看什么?

仅仅 DISTINCT 将无法完成这项工作,因为数据不会重复。您得到的实际上是部分交叉连接(导致部分笛卡尔积)。也就是说,您的联接条件不能确保#A 行与#B 行一一对应。发生这种情况时,对于#A 中的每一行,您将获得 B 中每个匹配行的输出行。2 x 2 = 4,而不是 2。

我认为如果你在你的例子中更具体一点会有所帮助。你实际上在查询什么?当然,你已经为我们简化了,但这也删除了所有上下文,让我们知道你在现实世界中想要完成什么。如果您尝试排列运动队,我们可能会给出不同的答案,而不是您尝试排列发票行项目或迟到事件或谁知道什么!

于 2012-11-23T19:55:15.110 回答
1

有了这些数据,只有这些数据,您无法获得您想要的结果,除非您可以为每个#A 的 ID 值提供某种方式来映射到每个 #B 的 ID 值。

因此,如果每个表中真的只有 2 条记录,它会是这样的:

SELECT *
FROM   #A a
   JOIN #B b
      ON a.str1 = b.str1  -- actually, if you join by IDs this isn't necessary
      AND a.str2 = b.str2 -- nor is this
      AND 
      (
          ( a.ID = 1 and b.ID = 7 )
       OR ( a.ID = 2 and b.ID = 8 )
      )

你得到的是一个笛卡尔积,其中#A 中的每条记录都与#B 中的每条匹配记录配对。由于每个表中有多个匹配记录,因此您可以从 A 和 B 中获得匹配记录的所有可能组合。

由于您必须使用的唯一其他字段是 ID 字段,因此您需要使用这些字段将一条 A 记录与一条 B 记录组合在一起。

于 2012-11-23T19:52:00.143 回答