0

[微软 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

我已经尝试了两个单独的 JOIN 的各种 UNION,但似乎无法摆脱无关的行......

  1. B LEFT JOIN A ON Acol2=Bcol1 UNION B LEFT JOIN A ON Acol2=Bcol2; 给出重复的行,因为联合的第二部分必须将 Bcol1 设置为 NULL(也许一种解决方案是删除这个重复的 NULL 行?)
  2. B INNER JOIN A ON Acol2=Bcol1 UNION B INNER JOIN A ON Acol2=Bcol2; 显然从 A 和 B 中删除了所有没有共享键的行(关于重新获得这些行的简单方法的解决方案?)

任何想法表示赞赏!

玩:[删除 SQL - 请参阅回复评论中的小提琴]

4

1 回答 1

4
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)

当您说 时no duplicates,这只有ACol2在 Table2 中的一行的一个字段中出现时才有可能。如果它出现在多个地方,你会得到重复。
- 如果可能的话,你想如何从 Table2 中选择哪条记录?


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

这是因为连接更喜欢 Table2 上的索引。但是,由于您永远不知道要加入哪个字段,因此没有一个索引可以满足加入条件。


编辑

使这显着更快的是创建一个规范化的TableB ...

 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)然后用and on索引该表(B_Val)...

然后B_ID在 non_normalised 表中包含该字段...

  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)

但这很混乱...

于 2012-11-14T13:40:55.283 回答