Sql 将表1连接到表2中的第1列或第2列,但不重复

Sql 将表1连接到表2中的第1列或第2列,但不重复,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,[MS SQL 2008] 我有表(所有列都是字符串名称): A:将某个数据字段与所属实体关联的两列 B:定义实体层次结构的三列 我需要创建整个层次结构的单个表(包括两个表中不存在的所有行),但表a中的键列(显示为Acol2)可以位于表B的第1列或第2列中 A: B: Acol1 | Acol2 Bcol1 | Bcol2 | Bcol3 -------+------ --------+--

[MS SQL 2008]

我有表(所有列都是字符串名称): A:将某个数据字段与所属实体关联的两列 B:定义实体层次结构的三列

我需要创建整个层次结构的单个表(包括两个表中不存在的所有行),但表a中的键列(显示为Acol2)可以位于表B的第1列或第2列中

A:                         B:
 Acol1 | Acol2                Bcol1 | Bcol2 | Bcol3
-------+------              --------+-------+------
   A   |   B                    B   |   X   |   Y
   C   |   D                    Q   |   X   |   Y
   E   |   F                    H   |   D   |   Z
   G   |   H                    W   |   V   |   U
输出应该是

Hierarchy:
 Acol1 | Bcol1 | Bcol2 | Bcol3
-------+-------+-------+------
   A   |   B   |   X   |  Y
  Null |   Q   |   X   |  Y
   C   |  Null |   D   |  Z
   G   |   H   |   D   |  Z
   E   |  Null |  Null | Null
  Null |   W   |   V   |  U 

Logic (also added to original):
    If A has no record in B, show A with all Null
    If A has record in Bcol1, show A with full row B
    If A has record in Bcol2, show A with Null, Bcol2, Bcol3
    If B has no record in A, show B with Null for Acol1
我尝试过两个独立连接的各种联合,但似乎无法摆脱无关的行

  • B在Acol2=Bcol1上左连接A联合B在Acol2=Bcol2上左连接A
    给出重复的行,因为联合的第二部分必须将Bcol1设置为NULL
    (可能有一种解决方案是删除此重复的空行?)
  • B内部联接A在Acol2=Bcol1上的联合B内部联接A在Acol2=Bcol2上的联合
    显然,删除A和B中没有共享键的所有行
    (关于仅恢复这些行的简单方法的解决方案?)
  • 任何想法都值得赞赏

    要玩: [SQL已删除-请参阅回复中的FIDLE注释]

    SELECT
      Table1.ACol1,
      CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
      Table2.BCol2,
      Table2.BCol3
    FROM
      Table1
    FULL OUTER JOIN
      Table2
        ON Table1.ACol2 IN (Table2.BCol1, Table2.BCol2)
    
    当您说
    无重复项
    时,只有当
    ACol2
    仅出现在表2中一行的一个字段中时,才可能出现这种情况。如果它出现在多个地方,您将得到重复。
    -如果可能的话,您希望如何从表2中选择哪个记录


    然而,一般来说,这是一种SQL反模式

    这是因为联接更喜欢表2中的索引。但是,由于您永远不知道要加入哪个字段,因此没有一个索引能够满足加入条件


    编辑

    创建一个标准化的表格B将大大加快这一速度

     B_ID | B_Col | B_Val
    ------+-------+-------
       1  |   1   |   B
       1  |   2   |   X
       1  |   3   |   Y
       2  |   1   |   Q
       2  |   2   |   X
       2  |   3   |   Y
       3  |   1   |   H
       3  |   2   |   D
       3  |   3   |   Z
       4  |   1   |   W
       4  |   2   |   V
       4  |   3   |   U
    
    然后用
    (B_ID)
    (B_Val)
    索引该表

    然后将
    B_ID
    字段包括在非标准化表格中

      ID  | Bcol1 | Bcol2 | Bcol3
    ------+-------+-------+-------
      1   |   B   |   X   |   Y
      2   |   Q   |   X   |   Y
      3   |   H   |   D   |   Z
      4   |   W   |   V   |   U
    
    然后使用以下查询

    SELECT
      Table1.ACol1,
      CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
      Table2.BCol2,
      Table2.BCol3
    FROM
      (
        Table1
      LEFT JOIN
        Table2Normalised
          ON  Table2Normalised.B_Val = Table1.ACol2
          AND Table2Normalised.B_Col IN (1,2)
      )
    FULL OUTER JOIN
      Table2
        ON Table2Normalised.B_ID = Table2.ID
    

    编辑:

    不更改模式,而是在BCol1上有一个索引,在Bcol2上有第二个索引

      SELECT ACol1, BCol1, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol1
      UNION ALL
      SELECT ACol1, NULL,  BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol2
      UNION ALL
      SELECT ACol1, NULL,  NULL,  NULL  FROM Table1 a WHERE NOT EXISTS (SELECT * FROM Table2 WHERE BCol1 = a.ACol2)
                                                        AND NOT EXISTS (SELECT * FROM Table2 WHERE BCol2 = a.ACol2)
      UNION ALL
      SELECT NULL,  BCol1, BCol2, BCol3 FROM Table2 b WHERE NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol1)
                                                        AND NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol2)
    
    但那太乱了

    当您说
    无重复项
    时,只有当
    ACol2
    仅出现在表2中一行的一个字段中时,才可能出现这种情况。如果它出现在多个地方,您将得到重复。
    -如果可能的话,您希望如何从表2中选择哪个记录


    然而,一般来说,这是一种SQL反模式

    这是因为联接更喜欢表2中的索引。但是,由于您永远不知道要加入哪个字段,因此没有一个索引能够满足加入条件


    编辑

    创建一个标准化的表格B将大大加快这一速度

     B_ID | B_Col | B_Val
    ------+-------+-------
       1  |   1   |   B
       1  |   2   |   X
       1  |   3   |   Y
       2  |   1   |   Q
       2  |   2   |   X
       2  |   3   |   Y
       3  |   1   |   H
       3  |   2   |   D
       3  |   3   |   Z
       4  |   1   |   W
       4  |   2   |   V
       4  |   3   |   U
    
    然后用
    (B_ID)
    (B_Val)
    索引该表

    然后将
    B_ID
    字段包括在非标准化表格中

      ID  | Bcol1 | Bcol2 | Bcol3
    ------+-------+-------+-------
      1   |   B   |   X   |   Y
      2   |   Q   |   X   |   Y
      3   |   H   |   D   |   Z
      4   |   W   |   V   |   U
    
    然后使用以下查询

    SELECT
      Table1.ACol1,
      CASE WHEN Table1.ACol1 = Table2.BCol1 THEN Table2.BCol1 ELSE NULL END AS BCol1
      Table2.BCol2,
      Table2.BCol3
    FROM
      (
        Table1
      LEFT JOIN
        Table2Normalised
          ON  Table2Normalised.B_Val = Table1.ACol2
          AND Table2Normalised.B_Col IN (1,2)
      )
    FULL OUTER JOIN
      Table2
        ON Table2Normalised.B_ID = Table2.ID
    

    编辑:

    不更改模式,而是在BCol1上有一个索引,在Bcol2上有第二个索引

      SELECT ACol1, BCol1, BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol1
      UNION ALL
      SELECT ACol1, NULL,  BCol2, BCol3 FROM Table1 a INNER JOIN Table2 b ON a.ACol2 = b.BCol2
      UNION ALL
      SELECT ACol1, NULL,  NULL,  NULL  FROM Table1 a WHERE NOT EXISTS (SELECT * FROM Table2 WHERE BCol1 = a.ACol2)
                                                        AND NOT EXISTS (SELECT * FROM Table2 WHERE BCol2 = a.ACol2)
      UNION ALL
      SELECT NULL,  BCol1, BCol2, BCol3 FROM Table2 b WHERE NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol1)
                                                        AND NOT EXISTS (SELECT * FROM Table1 WHERE ACol2 = b.BCol2)
    

    但这太麻烦了…

    你能为我们创建一个sql提琴吗?你能为我们创建一个sql提琴吗?效率有多低?@Woot4Moo-我同意,但我没有设计模式或功能需求。没错,只是等着手术给我们一个机会fiddle@Woot4Moo-我是为他做的:-)我不知道小提琴-从中学到的有用的东西,如果没有别的!这有多低效?@Woot4Moo-我同意,但我没有设计模式或功能需求。没错,只是等待OP给我们一个答案fiddle@Woot4Moo-我是为他做的:-)我不知道小提琴-从中学到的有用的东西,如果没有别的!