【问题标题】:SQL Joins and MS Access - How to combine multiple tables into one?SQL Joins 和 MS Access - 如何将多个表合并为一个?
【发布时间】:2014-08-25 00:45:27
【问题描述】:

我在 Access 2010 中有四个表,每个表都有相同的主键。我想将所有四个表中的所有数据连接到一个表中,其中每个值的列都与所有表的主键相关联。所以,例如:

Table1

ID   Value1

1    10       
2    7
3    4
4    12

Table 2

ID   Value2

1    33
2    8
6    19
7    4

Table 3

ID   Value3

1    99
2    99
5    99
7    99

我想创建:

Table 4

ID  Value1  Value2  Value3

1   10      33      99
2   7       8       99
3   4
4   12
5           99
6           19      
7           4       99

我正在使用 MS Access,我知道我必须基本上使用 3 个连接(左、右、内)来获得完全连接,但我不确定如何构建查询。

有人可以给我一些示例 SQL 代码来为我指明如何产生这个结果的正确方向吗?

这是我目前所拥有的。这结合了所有表格,但看起来我仍然缺少一些数据。我是不是做错了什么:

SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry LEFT JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) LEFT JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) LEFT JOIN OFSP ON Medicare.cptcode = OFSP.cptcode
UNION
SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry RIGHT JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) RIGHT JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) RIGHT JOIN OFSP ON Medicare.cptcode = OFSP.cptcode
UNION
SELECT Coventry.cptcode, Coventry.[Fee Schedule], CT6002.[Fee Schedule], Medicare.[Fee Schedule], OFSP.[Fee Schedule]
FROM ((Coventry INNER JOIN CT6002 ON Coventry.cptcode = CT6002.cptcode) INNER JOIN Medicare ON CT6002.cptcode = Medicare.cptcode) INNER JOIN OFSP ON Medicare.cptcode = OFSP.cptcode;

【问题讨论】:

  • 你用谷歌搜索了吗?
  • 是的,但我找不到能准确回答这个问题的任何东西。我找到了一些关于使用所有三个连接子句的信息,但是连接子句后面的 ON 子句似乎要求我有一些相等的字段,但我想提取所有字段,即使没有匹配项另一个表,例如我的问题示例中的记录 5。

标签: sql ms-access join ms-access-2010


【解决方案1】:

这个怎么样?

SELECT id
, max(v1) as value1
, max(v2) as value2
, max(v3) as value3
FROM 
(
    select id
    , value1 as v1
    , iif(true,null,value1) as v2
    , iif(true,null,value1) as v3 
    from Table1

    union 

    select id, null , value2 , null  from Table2

    union 

    select id, null , null , value3 as v3 from Table3
)
group by id
order by id

它是如何工作的:

  • 我没有进行连接,而是将所有结果放入一个“表”(我的子查询)中,但 value1、value2 和 value3 在它们自己的列中,并且对于不连接的表设置为 null '没有那些列。

  • 第一个查询中的iif 语句是说我希望v2 和v3 的数据类型与v1 相同。这是一个狡猾的黑客,但似乎有效(遗憾的是,访问从查询中的第一条语句中计算出类型,并且使用clng(null) 进行转换不起作用)。它们之所以起作用,是因为 iif 的结果必须与最后两个参数的类型相同,并且只有最后一个参数具有类型,因此可以从中推断出;而第一个参数为 true 意味着返回的值将永远是第二个参数。

  • 然后外部查询将这些结果压缩到每个 id 一行;由于具有值的字段大于 null,并且每个 id 最多有一个具有值的字段,因此我们为该列获取该值。

我不确定性能与 MS 文章的执行方式相比如何,但如果您使用访问权限,我怀疑您还有其他事情要担心 ;)。

SQL 小提琴:http://sqlfiddle.com/#!6/6f93b/2 (对于 SQL Server,因为 Access 不可用,但我已尝试使其尽可能相似)

【讨论】:

  • id、v1、v2、v3分别代表什么?
  • @Caulibrot:这些在子查询中定义。它们分别代表Value1、Value2和Value3;为了简洁起见,我称它们为v# 而不是value#,并避免与实际的列名混淆; ie 所以你可以很容易地分辨出我在哪里直接从表中提取数据与我在哪里做一些不同的事情(在这种情况下提取字段值或在源表不包含该列的情况下使用 null)。
【解决方案2】:

这是 JohnLBevan 答案的变体,如果 [Value1]、[Value2] 和 [Value3] 属于不同的类型,它将起作用。例如,与

表1

ID  Value1
--  ------
 1      10
 2       7
 3       4
 4      12

表2

ID  Value2      
--  ------------
 1  thirty-three
 2  eight       
 6  nineteen    
 7  four        

表3

ID  Value3    
--  ----------
 1  1999-01-01
 2  1999-01-01
 5  1999-01-01
 7  1999-01-01

查询

SELECT ID, MAX(v1) AS Value1, MAX(v2) AS Value2, MAX(v3) as Value3
FROM (
        SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
        FROM (SELECT COUNT(*) FROM Table1)
    UNION ALL
        SELECT ID, Value1 AS v1, NULL AS v2, NULL AS v3
        FROM Table1
    UNION ALL
        SELECT ID, NULL AS v1, Value2 AS v2, NULL AS v3
        FROM Table2
    UNION ALL
        SELECT ID, NULL AS v1, NULL AS v2, Value3 AS v3
        FROM Table3
)
WHERE ID > 0
GROUP BY ID

返回

ID  Value1  Value2        Value3    
--  ------  ------------  ----------
 1      10  thirty-three  1999-01-01
 2       7  eight         1999-01-01
 3       4                          
 4      12                          
 5                        1999-01-01
 6          nineteen                
 7          four          1999-01-01

说明:

UNION 子查询的第一部分使用虚拟值创建单行,以确保 UNION 的结果具有正确的列类型

SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
FROM (SELECT COUNT(*) FROM Table1)

返回

ID  v1  v2  v3        
--  --  --  ----------
 0   0      2001-01-01

UNION 子查询的其余部分附加每个表中的实际行

    SELECT 0 AS ID, 0 AS v1, '' AS v2, #2001-01-01# AS v3
    FROM (SELECT COUNT(*) FROM Table1)
UNION ALL
    SELECT ID, Value1 AS v1, NULL AS v2, NULL AS v3
    FROM Table1
UNION ALL
    SELECT ID, NULL AS v1, Value2 AS v2, NULL AS v3
    FROM Table2
UNION ALL
    SELECT ID, NULL AS v1, NULL AS v2, Value3 AS v3
    FROM Table3

给我们

ID  v1  v2            v3        
--  --  ------------  ----------
 0   0                2001-01-01
 1  10                          
 2   7                          
 3   4                          
 4  12                          
 1      thirty-three            
 2      eight                   
 6      nineteen                
 7      four                    
 1                    1999-01-01
 2                    1999-01-01
 5                    1999-01-01
 7                    1999-01-01

外部聚合查询排除具有虚拟值 (WHERE ID > 0) 的第一行,为每个 ID 提供一行 (GROUP BY ID),如果有一个 (如果没有,则为 Null)。

ID  Value1  Value2        Value3    
--  ------  ------------  ----------
 1      10  thirty-three  1999-01-01
 2       7  eight         1999-01-01
 3       4                          
 4      12                          
 5                        1999-01-01
 6          nineteen                
 7          four          1999-01-01

【讨论】:

  • 这与我需要的类似,但我不太了解语法。为什么使用 MAX,为什么选择 0 作为 ID?而 v1、v2、v3 的值又是从哪里来的?
  • 如果我有多个同名的表作为一个值,我可以将 v1 更改为 table1.v1,将 v2 更改为 table2.v2?
【解决方案3】:

创建所有表中所有 id 的并集,这样就可以得到 table4 中的 id 列。然后将这个联合封装在一个子选择(ids)中,并在这个子选择(父连接)和table1、table2、table3(子连接)之间创建左连接。然后选择你需要的...

SELECT 
ids.id, 
t1.Value1, 
t2.Value2, 
t3.Value3
FROM ((
(select id from table1 
union 
select id from table2
union 
select id from table3)  AS ids 
LEFT JOIN Table1 AS t1 ON ids.id = t1.ID) 
LEFT JOIN Table2 AS t2 ON ids.id = t2.ID) 
LEFT JOIN Table3 AS t3 ON ids.id = t3.ID;

【讨论】:

  • 比使用 max 好得多,但您可能想解释一下您在做什么。
  • 我的意思是你应该edit你的答案来解释你在做什么。尤其是为什么它优于公认的答案。
  • 从技术上讲,它应该产生相同的结果,因为 Id 是主键。但这可能会更快,因为它不涉及任何聚合函数。
猜你喜欢
  • 1970-01-01
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多