FULL JOIN

The FULL JOIN is often described as combining the LEFT JOIN and RIGHT JOIN operations. It returns all records from the left and right tables. Those records not satisfying the JOIN criteria are represented by NULLS. This join can be useful in instances where it is important to understand membership in both directions. In other words, to determine which records are in the left table but not in the right table, which records are in the right table but not in the left table, and which records are in both. You may be thinking, “when will I possibly need this?” That’s a very good question. Let’s examine a real-world problem and then explore why, when using this join type to retrieve data and subsequently report on it, extra caution is required.

The data used throughout the examples on this page and captured in the two tables below can be found at livesql.oracle.com.

Employees
The employees table contains one row per employee.

employee_idfirst_namelast_nameemailphone_numberhire_datejob_idsalarycommission_pctmanager_iddepartment_id
100StevenKingSKING515.123.456717-Jun-03AD_PRES2400090
101NeenaKochharNKOCHHAR515.123.456821-Sep-05AD_VP1700010090
102LexDe HaanLDEHAAN515.123.456913-Jan-01AD_VP1700010090
103AlexanderHunoldAHUNOLD590.423.45673-Jan-06IT_PROG900010260
104BruceErnstBERNST590.423.456821-May-07IT_PROG600010360
105DavidAustinDAUSTIN590.423.456925-Jun-05IT_PROG480010360
106ValliPataballaVPATABAL590.423.45605-Feb-06IT_PROG480010360
107DianaLorentzDLORENTZ590.423.55677-Feb-07IT_PROG420010360
108NancyGreenbergNGREENBE515.124.456917-Aug-02FI_MGR12008101100
109DanielFavietDFAVIET515.124.416916-Aug-02FI_ACCOUNT9000108100
110JohnChenJCHEN515.124.426928-Sep-05FI_ACCOUNT8200108100
111IsmaelSciarraISCIARRA515.124.436930-Sep-05FI_ACCOUNT7700108100
112Jose ManuelUrmanJMURMAN515.124.44697-Mar-06FI_ACCOUNT7800108100
113LuisPoppLPOPP515.124.45677-Dec-07FI_ACCOUNT6900108100
114DenRaphaelyDRAPHEAL515.127.45617-Dec-02PU_MAN1100010030
115AlexanderKhooAKHOO515.127.456218-May-03PU_CLERK310011430
116ShelliBaidaSBAIDA515.127.456324-Dec-05PU_CLERK290011430
117SigalTobiasSTOBIAS515.127.456424-Jul-05PU_CLERK280011430
118GuyHimuroGHIMURO515.127.456515-Nov-06PU_CLERK260011430
119KarenColmenaresKCOLMENA515.127.456610-Aug-07PU_CLERK250011430
120MatthewWeissMWEISS650.123.123418-Jul-04ST_MAN800010050
121AdamFrippAFRIPP650.123.223410-Apr-05ST_MAN820010050
122PayamKauflingPKAUFLIN650.123.32341-May-03ST_MAN790010050
123ShantaVollmanSVOLLMAN650.123.423410-Oct-05ST_MAN650010050
124KevinMourgosKMOURGOS650.123.523416-Nov-07ST_MAN580010050
125JuliaNayerJNAYER650.124.121416-Jul-05ST_CLERK320012050
126IreneMikkilineniIMIKKILI650.124.122428-Sep-06ST_CLERK270012050
127JamesLandryJLANDRY650.124.133414-Jan-07ST_CLERK240012050
128StevenMarkleSMARKLE650.124.14348-Mar-08ST_CLERK220012050
129LauraBissotLBISSOT650.124.523420-Aug-05ST_CLERK330012150
130MozheAtkinsonMATKINSO650.124.623430-Oct-05ST_CLERK280012150
131JamesMarlowJAMRLOW650.124.723416-Feb-05ST_CLERK250012150
132TJOlsonTJOLSON650.124.823410-Apr-07ST_CLERK210012150
133JasonMallinJMALLIN650.127.193414-Jun-04ST_CLERK330012250
134MichaelRogersMROGERS650.127.183426-Aug-06ST_CLERK290012250
135KiGeeKGEE650.127.173412-Dec-07ST_CLERK240012250
136HazelPhiltankerHPHILTAN650.127.16346-Feb-08ST_CLERK220012250
137RenskeLadwigRLADWIG650.121.123414-Jul-03ST_CLERK360012350
138StephenStilesSSTILES650.121.203426-Oct-05ST_CLERK320012350
139JohnSeoJSEO650.121.201912-Feb-06ST_CLERK270012350
140JoshuaPatelJPATEL650.121.18346-Apr-06ST_CLERK250012350
141TrennaRajsTRAJS650.121.800917-Oct-03ST_CLERK350012450
142CurtisDaviesCDAVIES650.121.299429-Jan-05ST_CLERK310012450
143RandallMatosRMATOS650.121.287415-Mar-06ST_CLERK260012450
144PeterVargasPVARGAS650.121.20049-Jul-06ST_CLERK250012450
145JohnRussellJRUSSEL011.44.1344.4292681-Oct-04SA_MAN140000.410080
146KarenPartnersKPARTNER011.44.1344.4672685-Jan-05SA_MAN135000.310080
147AlbertoErrazurizAERRAZUR011.44.1344.42927810-Mar-05SA_MAN120000.310080
148GeraldCambraultGCAMBRAU011.44.1344.61926815-Oct-07SA_MAN110000.310080
149EleniZlotkeyEZLOTKEY011.44.1344.42901829-Jan-08SA_MAN105000.210080
150PeterTuckerPTUCKER011.44.1344.12926830-Jan-05SA_REP100000.314580
151DavidBernsteinDBERNSTE011.44.1344.34526824-Mar-05SA_REP95000.2514580
152PeterHallPHALL011.44.1344.47896820-Aug-05SA_REP90000.2514580
153ChristopherOlsenCOLSEN011.44.1344.49871830-Mar-06SA_REP80000.214580
154NanetteCambraultNCAMBRAU011.44.1344.9876689-Dec-06SA_REP75000.214580
155OliverTuvaultOTUVAULT011.44.1344.48650823-Nov-07SA_REP70000.1514580
156JanetteKingJKING011.44.1345.42926830-Jan-04SA_REP100000.3514680
157PatrickSullyPSULLY011.44.1345.9292684-Mar-04SA_REP95000.3514680
158AllanMcEwenAMCEWEN011.44.1345.8292681-Aug-04SA_REP90000.3514680
159LindseySmithLSMITH011.44.1345.72926810-Mar-05SA_REP80000.314680
160LouiseDoranLDORAN011.44.1345.62926815-Dec-05SA_REP75000.314680
161SarathSewallSSEWALL011.44.1345.5292683-Nov-06SA_REP70000.2514680
162ClaraVishneyCVISHNEY011.44.1346.12926811-Nov-05SA_REP105000.2514780
163DanielleGreeneDGREENE011.44.1346.22926819-Mar-07SA_REP95000.1514780
164MatteaMarvinsMMARVINS011.44.1346.32926824-Jan-08SA_REP72000.114780
165DavidLeeDLEE011.44.1346.52926823-Feb-08SA_REP68000.114780
166SundarAndeSANDE011.44.1346.62926824-Mar-08SA_REP64000.114780
167AmitBandaABANDA011.44.1346.72926821-Apr-08SA_REP62000.114780
168LisaOzerLOZER011.44.1343.92926811-Mar-05SA_REP115000.2514880
169HarrisonBloomHBLOOM011.44.1343.82926823-Mar-06SA_REP100000.214880
170TaylerFoxTFOX011.44.1343.72926824-Jan-06SA_REP96000.214880
171WilliamSmithWSMITH011.44.1343.62926823-Feb-07SA_REP74000.1514880
172ElizabethBatesEBATES011.44.1343.52926824-Mar-07SA_REP73000.1514880
173SunditaKumarSKUMAR011.44.1343.32926821-Apr-08SA_REP61000.114880
174EllenAbelEABEL011.44.1644.42926711-May-04SA_REP110000.314980
175AlyssaHuttonAHUTTON011.44.1644.42926619-Mar-05SA_REP88000.2514980
176JonathonTaylorJTAYLOR011.44.1644.42926524-Mar-06SA_REP86000.214980
177JackLivingstonJLIVINGS011.44.1644.42926423-Apr-06SA_REP84000.214980
178KimberelyGrantKGRANT011.44.1644.42926324-May-07SA_REP70000.15149
179CharlesJohnsonCJOHNSON011.44.1644.4292624-Jan-08SA_REP62000.114980
180WinstonTaylorWTAYLOR650.507.987624-Jan-06SH_CLERK320012050
181JeanFleaurJFLEAUR650.507.987723-Feb-06SH_CLERK310012050
182MarthaSullivanMSULLIVA650.507.987821-Jun-07SH_CLERK250012050
183GirardGeoniGGEONI650.507.98793-Feb-08SH_CLERK280012050
184NanditaSarchandNSARCHAN650.509.187627-Jan-04SH_CLERK420012150
185AlexisBullABULL650.509.287620-Feb-05SH_CLERK410012150
186JuliaDellingerJDELLING650.509.387624-Jun-06SH_CLERK340012150
187AnthonyCabrioACABRIO650.509.48767-Feb-07SH_CLERK300012150
188KellyChungKCHUNG650.505.187614-Jun-05SH_CLERK380012250
189JenniferDillyJDILLY650.505.287613-Aug-05SH_CLERK360012250
190TimothyGatesTGATES650.505.387611-Jul-06SH_CLERK290012250
191RandallPerkinsRPERKINS650.505.487619-Dec-07SH_CLERK250012250
192SarahBellSBELL650.501.18764-Feb-04SH_CLERK400012350
193BritneyEverettBEVERETT650.501.28763-Mar-05SH_CLERK390012350
194SamuelMcCainSMCCAIN650.501.38761-Jul-06SH_CLERK320012350
195VanceJonesVJONES650.501.487617-Mar-07SH_CLERK280012350
196AlanaWalshAWALSH650.507.981124-Apr-06SH_CLERK310012450
197KevinFeeneyKFEENEY650.507.982223-May-06SH_CLERK300012450
198DonaldOConnellDOCONNEL650.507.983321-Jun-07SH_CLERK260012450
199DouglasGrantDGRANT650.507.984413-Jan-08SH_CLERK260012450
200JenniferWhalenJWHALEN515.123.444417-Sep-03AD_ASST440010110
201MichaelHartsteinMHARTSTE515.123.555517-Feb-04MK_MAN1300010020
202PatFayPFAY603.123.666617-Aug-05MK_REP600020120
203SusanMavrisSMAVRIS515.123.77777-Jun-02HR_REP650010140
204HermannBaerHBAER515.123.88887-Jun-02PR_REP1000010170
205ShelleyHigginsSHIGGINS515.123.80807-Jun-02AC_MGR12008101110
206WilliamGietzWGIETZ515.123.81817-Jun-02AC_ACCOUNT8300205110

Departments
The departments table contains one row per department.

department_iddepartment_namemanager_idlocation_id
10Administration2001700
20Marketing2011800
30Purchasing1141700
40Human Resources2032400
50Shipping1211500
60IT1031400
70Public Relations2042700
80Sales1452500
90Executive1001700
100Finance1081700
110Accounting2051700
120Treasury1700
130Corporate Tax1700
140Control And Credit1700
150Shareholder Services1700
160Benefits1700
170Manufacturing1700
180Construction1700
190Contracting1700
200Operations1700
210IT Support1700
220NOC1700
230IT Helpdesk1700
240Government Sales1700
250Retail Sales1700
260Recruiting1700
270Payroll1700

Real-world Problem
Suppose you work at a company and you’ve been requested to generate a report for management with a focus on understanding each department and the employees within them. A key requirement of this report is that every department and employee are represented in the report. As a result, management will be able to review records of employees currently working in a department, records of employees not currently assigned to a department, and those departments without any employees (i.e., a vacant department). This is clearly a job for the FULL JOIN.

Below is the code required to generate this report and the corresponding result set or content of the report. For the purposes of this example, only a subset of attributes from the employees and departments tables have been used.

-- Generate report for management containing all employees and departments.
SELECT
    hr.employees.employee_id,
    hr.employees.hire_date,
    hr.employees.department_id,
    hr.departments.department_name,
    hr.employees.job_id,
    hr.employees.salary,
    hr.employees.commission_pct,
    hr.employees.manager_id
FROM
    hr.employees
    FULL JOIN
    hr.departments
        ON hr.employees.department_id = hr.departments.department_id
ORDER BY
    hr.employees.employee_id;
employee_idhire_datedepartment_iddepartment_namejob_idsalarycommission_pctmanager_id
10017-Jun-0390ExecutiveAD_PRES24000
10121-Sep-0590ExecutiveAD_VP17000100
10213-Jan-0190ExecutiveAD_VP17000100
1033-Jan-0660ITIT_PROG9000102
10421-May-0760ITIT_PROG6000103
10525-Jun-0560ITIT_PROG4800103
1065-Feb-0660ITIT_PROG4800103
1077-Feb-0760ITIT_PROG4200103
10817-Aug-02100FinanceFI_MGR12008101
10916-Aug-02100FinanceFI_ACCOUNT9000108
11028-Sep-05100FinanceFI_ACCOUNT8200108
11130-Sep-05100FinanceFI_ACCOUNT7700108
1127-Mar-06100FinanceFI_ACCOUNT7800108
1137-Dec-07100FinanceFI_ACCOUNT6900108
1147-Dec-0230PurchasingPU_MAN11000100
11518-May-0330PurchasingPU_CLERK3100114
11624-Dec-0530PurchasingPU_CLERK2900114
11724-Jul-0530PurchasingPU_CLERK2800114
11815-Nov-0630PurchasingPU_CLERK2600114
11910-Aug-0730PurchasingPU_CLERK2500114
12018-Jul-0450ShippingST_MAN8000100
12110-Apr-0550ShippingST_MAN8200100
1221-May-0350ShippingST_MAN7900100
12310-Oct-0550ShippingST_MAN6500100
12416-Nov-0750ShippingST_MAN5800100
12516-Jul-0550ShippingST_CLERK3200120
12628-Sep-0650ShippingST_CLERK2700120
12714-Jan-0750ShippingST_CLERK2400120
1288-Mar-0850ShippingST_CLERK2200120
12920-Aug-0550ShippingST_CLERK3300121
13030-Oct-0550ShippingST_CLERK2800121
13116-Feb-0550ShippingST_CLERK2500121
13210-Apr-0750ShippingST_CLERK2100121
13314-Jun-0450ShippingST_CLERK3300122
13426-Aug-0650ShippingST_CLERK2900122
13512-Dec-0750ShippingST_CLERK2400122
1366-Feb-0850ShippingST_CLERK2200122
13714-Jul-0350ShippingST_CLERK3600123
13826-Oct-0550ShippingST_CLERK3200123
13912-Feb-0650ShippingST_CLERK2700123
1406-Apr-0650ShippingST_CLERK2500123
14117-Oct-0350ShippingST_CLERK3500124
14229-Jan-0550ShippingST_CLERK3100124
14315-Mar-0650ShippingST_CLERK2600124
1449-Jul-0650ShippingST_CLERK2500124
1451-Oct-0480SalesSA_MAN140000.4100
1465-Jan-0580SalesSA_MAN135000.3100
14710-Mar-0580SalesSA_MAN120000.3100
14815-Oct-0780SalesSA_MAN110000.3100
14929-Jan-0880SalesSA_MAN105000.2100
15030-Jan-0580SalesSA_REP100000.3145
15124-Mar-0580SalesSA_REP95000.25145
15220-Aug-0580SalesSA_REP90000.25145
15330-Mar-0680SalesSA_REP80000.2145
1549-Dec-0680SalesSA_REP75000.2145
15523-Nov-0780SalesSA_REP70000.15145
15630-Jan-0480SalesSA_REP100000.35146
1574-Mar-0480SalesSA_REP95000.35146
1581-Aug-0480SalesSA_REP90000.35146
15910-Mar-0580SalesSA_REP80000.3146
16015-Dec-0580SalesSA_REP75000.3146
1613-Nov-0680SalesSA_REP70000.25146
16211-Nov-0580SalesSA_REP105000.25147
16319-Mar-0780SalesSA_REP95000.15147
16424-Jan-0880SalesSA_REP72000.1147
16523-Feb-0880SalesSA_REP68000.1147
16624-Mar-0880SalesSA_REP64000.1147
16721-Apr-0880SalesSA_REP62000.1147
16811-Mar-0580SalesSA_REP115000.25148
16923-Mar-0680SalesSA_REP100000.2148
17024-Jan-0680SalesSA_REP96000.2148
17123-Feb-0780SalesSA_REP74000.15148
17224-Mar-0780SalesSA_REP73000.15148
17321-Apr-0880SalesSA_REP61000.1148
17411-May-0480SalesSA_REP110000.3149
17519-Mar-0580SalesSA_REP88000.25149
17624-Mar-0680SalesSA_REP86000.2149
17723-Apr-0680SalesSA_REP84000.2149
17824-May-07SA_REP70000.15149
1794-Jan-0880SalesSA_REP62000.1149
18024-Jan-0650ShippingSH_CLERK3200120
18123-Feb-0650ShippingSH_CLERK3100120
18221-Jun-0750ShippingSH_CLERK2500120
1833-Feb-0850ShippingSH_CLERK2800120
18427-Jan-0450ShippingSH_CLERK4200121
18520-Feb-0550ShippingSH_CLERK4100121
18624-Jun-0650ShippingSH_CLERK3400121
1877-Feb-0750ShippingSH_CLERK3000121
18814-Jun-0550ShippingSH_CLERK3800122
18913-Aug-0550ShippingSH_CLERK3600122
19011-Jul-0650ShippingSH_CLERK2900122
19119-Dec-0750ShippingSH_CLERK2500122
1924-Feb-0450ShippingSH_CLERK4000123
1933-Mar-0550ShippingSH_CLERK3900123
1941-Jul-0650ShippingSH_CLERK3200123
19517-Mar-0750ShippingSH_CLERK2800123
19624-Apr-0650ShippingSH_CLERK3100124
19723-May-0650ShippingSH_CLERK3000124
19821-Jun-0750ShippingSH_CLERK2600124
19913-Jan-0850ShippingSH_CLERK2600124
20017-Sep-0310AdministrationAD_ASST4400101
20117-Feb-0420MarketingMK_MAN13000100
20217-Aug-0520MarketingMK_REP6000201
2037-Jun-0240Human ResourcesHR_REP6500101
2047-Jun-0270Public RelationsPR_REP10000101
2057-Jun-02110AccountingAC_MGR12008101
2067-Jun-02110AccountingAC_ACCOUNT8300205
Shareholder Services
IT Helpdesk
Corporate Tax
Manufacturing
Treasury
NOC
Control And Credit
Recruiting
Contracting
Retail Sales
Government Sales
Construction
Payroll
Operations
Benefits
IT Support

Notice, within the first 107 records, 106 employees are actively assigned to a department, as indicated by the department attributes being populated. Employee 178 is not currently assigned to a department. Following those 107 records, there exists 16 records representing the vacant departments (e.g., Recruiting, Treasuring, etc.). These facts are the result of the ON clause where the condition is to evaluate whether the department ID populated in the employee record can be found within the departments table and/or the department ID populated in the department record can be found within the employees table. With the output of the query, the reporting requirements have been fulfilled.

A Tale of Caution
Developing reports and/or dashboards using result sets generated, in whole or in part, by a FULL JOIN require additional attention to detail. For example, using the result set above, how many employees are there? The correct answer is 107; however, a typically safe method of computing this value will return an incorrect value of 123. See the query below where the importance of understanding the difference between COUNT(*) and COUNT(schema.table.column_name) is critical to reporting accuracy.

-- The query returns 123 but the correct number of employees is 107.
WITH report AS (
    SELECT
    hr.employees.employee_id,
    hr.employees.hire_date,
    hr.employees.department_id,
    hr.departments.department_name,
    hr.employees.job_id,
    hr.employees.salary,
    COALESCE(hr.employees.commission_pct, 0) AS commission_percentage,
    hr.employees.manager_id
FROM
    hr.employees
    FULL JOIN
    hr.departments
        ON hr.employees.department_id = hr.departments.department_id
)
SELECT
	COUNT(*) AS employee_count
FROM
	report;

Reporting and visualization tools, such as Tableau and Power BI can make the same error without additional input from the user specifying to ignore those records with unpopulated employee ID values.

The potential issues with reporting on data generated by a FULL JOIN do not only include instances where counts are computed. It’s potentially an issue when computing any type of aggregation. Imagine that all employees should have a commission percentage value populated and you’ve taken the extra step of replacing missing employee commission percentage values with zero for the users of your report. Subsequently, you or a user of your report computes an average of the commission percentage values using the query below or a popular reporting tool, such as Tableau or Power BI. The average commission percentage will be dragged down due to the rows in the report representing vacant departments. Instead of returning a value of 0.22, the value returned will be 0.06.

-- Compute the average employee commission percentage across all employees.
WITH report AS (
    SELECT
    hr.employees.employee_id,
    hr.employees.hire_date,
    hr.employees.department_id,
    hr.departments.department_name,
    hr.employees.job_id,
    hr.employees.salary,
    COALESCE(hr.employees.commission_pct, 0) AS commission_percentage,
    hr.employees.manager_id
FROM
    hr.employees
    FULL JOIN
    hr.departments
        ON hr.employees.department_id = hr.departments.department_id
)
SELECT
	ROUND(
    	AVG(report.commission_percentage),
    	2
    ) AS commission_percentage
FROM
    report;

The examples and ideas captured above are not intended to convey an anti-FULL JOIN position or stance, but serve to simply educate on things that can go wrong, resulting in inaccurate data reported, when we are not careful.

Knowledge Check
If you’d like to confirm your understanding on JOINS and other fundamental concepts, consider solving a handful of my practice problems here.