Simulate FULL OUTER JOIN with Access on more than two tables

前端 未结 1 1779
闹比i
闹比i 2020-12-12 02:05

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 havin

相关标签:
1条回答
  • 2020-12-12 02:55

    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.

    0 讨论(0)
提交回复
热议问题