Simulate FULL OUTER JOIN with Access on more than two tables

旧巷老猫 提交于 2019-11-27 19:32:50

问题


I learned the hard way that Access does not allow you to do full outer joins, and while reading on how to simulate one, I have begun to understand how to do so, but am having issues trying to apply this to more than just two tables.

Is it as simple as doing the following?

SELECT * FROM table1
LEFT JOIN table2 ON table1.field = table2.field
LEFT JOIN table3 ON table1.field = table3.field
UNION
SELECT * FROM table1
RIGHT JOIN table2 ON table1.field = table2.field
RIGHT JOIN table3 ON table1.field = table3.field

回答1:


A quick search of the web revealed that the subject of simulating a FULL OUTER JOIN ("FOJ") has been discussed many times on Stack Overflow and elsewhere, but the answers all seem to limit themselves to the case with only two tables. I suspected it was because a FOJ on three or more tables was

  1. not a very common occurrence, and
  2. potentially quite messy.

Still, I thought I'd give it a go, and here's what I came up with:

The technique most commonly mentioned for simulating a FOJ on two tables is to UNION ALL the three possible cases:

In_Table2  In_Table1
---------  ---------
false      true
true       false
true       true

or, substituting true=1 and false=0

In_Table2  In_Table1
---------  ---------
0          1
1          0
1          1

That looks like a two-bit integer with three possible non-zero values, and the SQL to extract those would be of the form

Table2 RIGHT JOIN Table1 WHERE Table2.something IS NULL
UNION ALL
Table2 LEFT JOIN Table1 WHERE Table1.something IS NULL
UNION ALL
Table2 INNER JOIN Table1

The state table for the case with three tables would therefore look like a three-bit integer with seven possible non-zero values

In_Table3  In_Table2  In_Table1
---------  ---------  ---------
0          0          1
0          1          0
0          1          1
1          0          0
1          0          1
1          1          0
1          1          1

I wanted to do the join on an integer value, so I just assigned them sequentially for each of the seven rows

Table3  Table2  Table1
------  ------  ------
                1
        2       
        3       3
4               
5               5
6       6       
7       7       7

so my test tables were

[Table1]

n  txt 
-  ----
1  t1_1
3  t1_3
5  t1_5
7  t1_7

[Table2]

n  txt 
-  ----
2  t2_2
3  t2_3
6  t2_6
7  t2_7

[Table3]

n  txt 
-  ----
4  t3_4
5  t3_5
6  t3_6
7  t3_7

I created a saved query in Access named [foj12] to perform the FOJ between [Table1] and [Table2]

    SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
    FROM
        Table1 t1
        INNER JOIN
        Table2 t2
            ON t1.n = t2.n
UNION ALL
    SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
    FROM
        Table1 t1
        LEFT JOIN
        Table2 t2
            ON t1.n = t2.n
    WHERE t2.n IS NULL
UNION ALL 
    SELECT t1.n AS t1_n, t1.txt AS t1_txt, t2.n AS t2_n, t2.txt AS t2_txt
    FROM
        Table1 t1
        RIGHT JOIN
        Table2 t2
            ON t1.n = t2.n
    WHERE t1.n IS NULL

It returns

t1_n  t1_txt  t2_n  t2_txt
----  ------  ----  ------
   1  t1_1                
                 2  t2_2  
   3  t1_3       3  t2_3  
   5  t1_5                
                 6  t2_6  
   7  t1_7       7  t2_7  

Then I started working through the cases involving [Table3]. They were as follows, and correspond to the "unioned" queries in the SQL statement below.

  1. Table3 matches both Table1 and Table2 (n=7)
  2. Table3 matches Table1 but not Table2 (n=5)
  3. Table3 matches Table2 but not Table1 (n=6)
  4. rows in Table3 that don't match anything in Table1 or Table2 (n=4)
  5. rows in FOJ(Table1,Table2) that have nothing in common with Table3 (n=1,2,3)
    SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
    FROM
        Table3 t3
        INNER JOIN
        foj12 f
            ON t3.n = f.t1_n AND t3.n = f.t2_n
UNION ALL
    SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
    FROM
        Table3 t3
        INNER JOIN
        foj12 f
            ON t3.n = f.t1_n
    WHERE f.t2_n IS NULL
UNION ALL
    SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, t3.n AS t3_n, t3.txt AS t3_txt
    FROM
        Table3 t3
        INNER JOIN
        foj12 f
            ON t3.n = f.t2_n
    WHERE f.t1_n IS NULL
UNION ALL
    SELECT NULL, NULL, NULL, NULL, t3.n AS t3_n, t3.txt AS t3_txt
    FROM
        Table3 t3
    WHERE t3.n NOT IN (SELECT t1_n FROM foj12 WHERE t1_n IS NOT NULL)
        AND t3.n NOT IN (SELECT t2_n FROM foj12 WHERE t2_n IS NOT NULL)
UNION ALL
    SELECT f.t1_n, f.t1_txt, f.t2_n, f.t2_txt, NULL, NULL
    FROM foj12 f
    WHERE 
        (f.t1_n NOT IN (SELECT n FROM Table3) AND f.t2_n NOT IN (SELECT n FROM Table3))
        OR
        (f.t1_n NOT IN (SELECT n FROM Table3) AND f.t2_n IS NULL)
        OR
        (f.t1_n IS NULL AND f.t2_n NOT IN (SELECT n FROM Table3))
ORDER BY 5, 3, 1

That little beauty returns

t1_n  t1_txt  t2_n  t2_txt  t3_n  t3_txt
----  ------  ----  ------  ----  ------
   1  t1_1                              
                 2  t2_2                
   3  t1_3       3  t2_3                
                               4  t3_4  
   5  t1_5                     5  t3_5  
                 6  t2_6       6  t3_6  
   7  t1_7       7  t2_7       7  t3_7  

(Needless to say I'm not interested in adding a fourth table! :)

Comments welcome.



来源:https://stackoverflow.com/questions/24700881/simulate-full-outer-join-with-access-on-more-than-two-tables

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!