问题
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
- not a very common occurrence, and
- 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.
- Table3 matches both Table1 and Table2 (n=7)
- Table3 matches Table1 but not Table2 (n=5)
- Table3 matches Table2 but not Table1 (n=6)
- rows in Table3 that don't match anything in Table1 or Table2 (n=4)
- 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