【问题标题】:Joining 3 tables and retrieve all the records from all the tables连接 3 个表并从所有表中检索所有记录
【发布时间】:2009-01-14 04:42:49
【问题描述】:

我正在连接三个表(执行完全外部连接),以便我可以从所有表中检索所有记录。我面临的问题是我加入表格的顺序。

表信息

alt text http://img235.imageshack.us/img235/7980/tableinfoow1.png

(1) 如果我以 TABLE1、TABLE2、TABLE3 顺序连接表,我会得到两行记录,用于团队 B 和级别 1。

SELECT DISTINCT 
    (CASE WHEN T0.[TEAM] IS NOT NULL THEN T0.[TEAM] WHEN T1.[TEAM] IS NOT NULL THEN T1.[TEAM] WHEN T2.[TEAM] IS NOT NULL THEN T2.[TEAM] ELSE T0.[TEAM] END) AS [TEAM], 
    (CASE WHEN T0.[LEVEL] IS NOT NULL THEN T0.[LEVEL] WHEN T1.[LEVEL] IS NOT NULL THEN T1.[LEVEL] WHEN T2.[LEVEL] IS NOT NULL THEN T2.[LEVEL] ELSE T0.[LEVEL] END) AS [LEVEL], 
    T0.[VALUE1] AS [VALUE1], 
    T1.[VALUE2] AS [VALUE2], 
    T2.[VALUE3] AS [VALUE3] 

FROM TABLE1 T0
FULL JOIN TABLE2 T1 ON T0.[TEAM] = T1.[TEAM] AND T0.[LEVEL] = T1.[LEVEL] 
FULL JOIN TABLE3 T2 ON T0.[TEAM] = T2.[TEAM] AND T0.[LEVEL] = T2.[LEVEL]

(2) 如果我加入 TABLE2、TABLE3、TABLE1 序列中的表,我会在输出中得到正确的行数。

SELECT DISTINCT 
    (CASE WHEN T0.[TEAM] IS NOT NULL THEN T0.[TEAM] WHEN T1.[TEAM] IS NOT NULL THEN T1.[TEAM] WHEN T2.[TEAM] IS NOT NULL THEN T2.[TEAM] ELSE T0.[TEAM] END) AS [TEAM], 
    (CASE WHEN T0.[LEVEL] IS NOT NULL THEN T0.[LEVEL] WHEN T1.[LEVEL] IS NOT NULL THEN T1.[LEVEL] WHEN T2.[LEVEL] IS NOT NULL THEN T2.[LEVEL] ELSE T0.[LEVEL] END) AS [LEVEL], 
    T0.[VALUE1] AS [VALUE1], 
    T1.[VALUE2] AS [VALUE2], 
    T2.[VALUE3] AS [VALUE3] 

FROM TABLE2 T0
FULL JOIN TABLE3 T1 ON T0.[TEAM] = T1.[TEAM] AND T0.[LEVEL] = T1.[LEVEL] 
FULL JOIN TABLE1 T2 ON T0.[TEAM] = T2.[TEAM] AND T0.[LEVEL] = T2.[LEVEL]

我面临的问题是我不知道输入表并在运行时将所有这些表作为用户的输入并执行连接。我不能一次合并两个表,因为从技术上讲,我的表一次可以合并三个以上的表(最多 9 个或 10 个)。

如何确保从所有表中获取所有记录(使用完全外连接),但不会像 #1 中那样获取两行。

【问题讨论】:

  • 我目前没有时间为此生成查询,但也许您应该真的重新考虑您的数据库结构。
  • +1 重新思考数据模型
  • 我正在编写一个允许用户合并文件的 ETL 应用程序,因此我需要执行此操作。当然这不是我的应用程序数据库设计的一部分:-)

标签: sql database join multiple-tables


【解决方案1】:

如果这是你需要的:

TEAM LEVEL  Value1  Value2  Value3
A   1        1       NULL    NULL
B   1        NULL    1000    900

然后您可以通过以下方式实现:

SELECT [TEAM], [LEVEL], MAX(v1) Value1, MAX(v2) Value2, MAX(v3) Value3
FROM (
    SELECT [TEAM], [LEVEL], Value1 v1, NULL v2, NULL v3
    FROM TABLE1
    UNION
    SELECT [TEAM], [LEVEL], NULL, Value2, NULL
    FROM TABLE2
    UNION
    SELECT [TEAM], [LEVEL], NULL, NULL, Value3
    FROM TABLE3
) t0
GROUP BY [TEAM], [LEVEL]

您可以根据需要使用任意数量的表格。

【讨论】:

  • Union 被建议作为 FULL OUTER JOIN 的一般替代方法:weblogs.sqlteam.com/jeffs/archive/2007/04/19/… 但是,如果您必须使用完全外连接,我认为您必须使用嵌套子查询,因此您只连接两个结果集在这样的时间:SELECT * FROM (t1 FULL JOIN t2 ON (t1.c1 = t2.c1)) FULL JOIN t3 ON (t1.c1 = t3.c1);
【解决方案2】:

这就是 FULL OUTER JOIN 的定义(当使用它时,几乎总是表明设计不佳 - 我大约每年使用一次 FULL OUTER JOIN)。

如果你给出了你想要的结果?

我在考虑 UNION、GROUP BY 和 COALESCE。

【讨论】:

    【解决方案3】:

    您需要在第二个连接表达式上添加一个额外的匹配条件,以允许它匹配第二个表的团队/级别值。我还使用 ISNULL 简化了团队/级别列表达式:

    SELECT DISTINCT 
        ISNULL(T0.[TEAM],ISNULL(T1.[TEAM],T2.[TEAM])) AS [TEAM],
        ISNULL(T0.[LEVEL],ISNULL(T1.[LEVEL],T2.[LEVEL])) AS [LEVEL],
        T0.[VALUE1], T1.[VALUE2], T2.[VALUE3]     
    FROM TABLE1 T0
    FULL JOIN TABLE2 T1 ON T0.[TEAM] = T1.[TEAM] AND T0.[LEVEL] = T1.[LEVEL] 
    FULL JOIN TABLE3 T2 ON (T0.[TEAM] = T2.[TEAM] AND T0.[LEVEL] = T2.[LEVEL])
                        OR (T1.[TEAM] = T2.[TEAM] AND T1.[LEVEL] = T2.[LEVEL])
    

    看到了吗? T1 未与 T2 显示在同一行,因为您从未允许将其作为匹配的可能性。

    【讨论】:

      【解决方案4】:

      正如你在 yru 查询中定义的 distinct,这意味着在这个联合中存在多个条目,所有都是最好的,因为数据中有重复。

      SELECT [TEAM], [LEVEL], MAX(v1) Value1, MAX(v2) Value2, MAX(v3) Value3
      FROM (
          SELECT [TEAM], [LEVEL],  v1, NULL v2, NULL v3
          FROM TABLE1
          UNION ALL
          SELECT [TEAM], [LEVEL], NULL v1, V2, NULL v3
          FROM TABLE2
          UNION ALL
          SELECT [TEAM], [LEVEL], NULL V1, NULL V2, V3
          FROM TABLE3
      ) t0
      GROUP BY [TEAM], [LEVEL]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多