In my experience, the SELF JOIN is almost as rare as the CROSS JOIN. This is due to the limited opportunities existing in most data to actually make use of it. It is particularly useful when attempting to capture hierarchal relationships or simply when there is a need to capture data, existing across multiple rows, within a single row. While this join type is often referred to as a SELF JOIN, in practice, it’s a LEFT JOIN with the same table on both sides of the LEFT JOIN keywords. Each instance requires a different name, so table aliases are a must. This eliminates the table and column ambiguity that would otherwise occur in the ON and SELECT clauses.
One common example can be found within the data responsible for capturing information on a company’s products and the corresponding product categories. Each product belongs within a category and that category may roll-up to another, broader category. The purpose of this broader or parent category is to group related categories together. Another common example can be found in human resource data where there exists a relationship between managers and employees. Typically, a manager has one or more employees, and an employee directly reports to one manager.
Let’s explore both examples, individually, and then walk through an example that is not so common. The data used in the first two examples on this page can be found at livesql.oracle.com.
Product Category Relationships
In this example, we’ll use the categories table below. Within this table, there is one row per product category. Within each row, the parent category ID value associated with the specific category’s parent category, if one exists, is recorded. By having the parent category ID within each row, we can gather each category’s parent information by traversing the same table and finding where the parent category ID exists as a category ID. For example, the category, “hardware1” has a parent category ID value of 10. In the row above, this parent category ID value can be found within the category ID column. Therefore, “hardware” is the parent category of “hardware1” and has a category description of “computer hardware and peripherals.”
| category_name | category_description | category_id | parent_category_id |
|---|---|---|---|
| hardware | computer hardware and peripherals | 10 | 90 |
| hardware1 | monitors | 11 | 10 |
| hardware2 | printers | 12 | 10 |
| hardware3 | harddisks | 13 | 10 |
| hardware4 | memory components/upgrades | 14 | 10 |
| hardware5 | processors, sound and video cards, network cards, motherboards | 15 | 10 |
| hardware6 | keyboards, mouses, mouse pads | 16 | 10 |
| hardware7 | other peripherals (CD-ROM, DVD, tape cartridge drives, …) | 17 | 10 |
| hardware8 | miscellaneous hardware (cables, screws, power supplies …) | 19 | 10 |
| software | computer software | 20 | 90 |
| software1 | spreadsheet software | 21 | 20 |
| software2 | word processing software | 22 | 20 |
| software3 | database software | 23 | 20 |
| software4 | operating systems | 24 | 20 |
| software5 | software development tools (including languages) | 25 | 20 |
| software6 | miscellaneous software | 29 | 20 |
| office equipment | office furniture and supplies | 30 | 90 |
| office1 | capitalizable assets (desks, chairs, phones …) | 31 | 30 |
| office2 | office supplies for daily use (pencils, erasers, staples, …) | 32 | 30 |
| office3 | manuals, other books | 33 | 30 |
| office4 | miscellaneous office supplies | 39 | 30 |
| online catalog | catalog of computer hardware, software, and office equipment | 90 | – |
This same process can be carried out manually for each category; however, the goal is to approach this programmatically by using two aliased instances of the categories table in a LEFT JOIN operation. The ON clause will contain the same instructions we processed manually when traversing the rows for matches. When a match is found, the category’s parent information, if it exists, will be represented within the same row, side by side.
Below is the code used to achieve this task and the corresponding result set. I’ve ordered the result set by the child category ID for readability.
-- Retrieve each category and category's parent category information within the same row.
SELECT
child_category.category_id,
child_category.category_name,
child_category.category_description,
parent_category.category_id AS parent_category_id,
parent_category.category_name AS parent_category_name,
parent_category.category_description AS parent_category_description
FROM
oe.categories_tab child_category
LEFT JOIN
oe.categories_tab parent_category
ON child_category.parent_category_id = parent_category.category_id
ORDER BY
child_category.category_id;
| category_id | category_name | category_description | parent_category_id | parent_category_name | parent_category_description |
|---|---|---|---|---|---|
| 10 | hardware | computer hardware and peripherals | 90 | online catalog | catalog of computer hardware, software, and office equipment |
| 11 | hardware1 | monitors | 10 | hardware | computer hardware and peripherals |
| 12 | hardware2 | printers | 10 | hardware | computer hardware and peripherals |
| 13 | hardware3 | harddisks | 10 | hardware | computer hardware and peripherals |
| 14 | hardware4 | memory components/upgrades | 10 | hardware | computer hardware and peripherals |
| 15 | hardware5 | processors, sound and video cards, network cards, motherboards | 10 | hardware | computer hardware and peripherals |
| 16 | hardware6 | keyboards, mouses, mouse pads | 10 | hardware | computer hardware and peripherals |
| 17 | hardware7 | other peripherals (CD-ROM, DVD, tape cartridge drives, …) | 10 | hardware | computer hardware and peripherals |
| 19 | hardware8 | miscellaneous hardware (cables, screws, power supplies …) | 10 | hardware | computer hardware and peripherals |
| 20 | software | computer software | 90 | online catalog | catalog of computer hardware, software, and office equipment |
| 21 | software1 | spreadsheet software | 20 | software | computer software |
| 22 | software2 | word processing software | 20 | software | computer software |
| 23 | software3 | database software | 20 | software | computer software |
| 24 | software4 | operating systems | 20 | software | computer software |
| 25 | software5 | software development tools (including languages) | 20 | software | computer software |
| 29 | software6 | miscellaneous software | 20 | software | computer software |
| 30 | office equipment | office furniture and supplies | 90 | online catalog | catalog of computer hardware, software, and office equipment |
| 31 | office1 | capitalizable assets (desks, chairs, phones …) | 30 | office equipment | office furniture and supplies |
| 32 | office2 | office supplies for daily use (pencils, erasers, staples, …) | 30 | office equipment | office furniture and supplies |
| 33 | office3 | manuals, other books | 30 | office equipment | office furniture and supplies |
| 39 | office4 | miscellaneous office supplies | 30 | office equipment | office furniture and supplies |
| 90 | online catalog | catalog of computer hardware, software, and office equipment | – | – | – |
Notice how the row corresponding to category ID 90 (i.e., online catalog) doesn’t contain parent category information. This is because it doesn’t have one.
Employee-Manager Relationships
In this example, we’ll use the employees table below. Within this table, there is one row per employee. Within each row, the manager ID value associated with the specific employee’s manager is recorded. The absence of a manager ID value is indicative of an employee not reporting directly to another employee, or more simply put, an unmanaged employee. Because each employee’s manager ID value is captured within the same row, we can gather the employee’s manager information by traversing the same table and finding the row where the manager ID value exists as an employee ID value. For example, Neena Kochhar (i.e., employee ID 101) reports to the employee with an employee ID value of 100. Based on the table, this employee ID value corresponds to Steven King.
| employee_id | first_name | last_name | phone_number | hire_date | job_id | salary | commission_pct | manager_id | department_id | |
|---|---|---|---|---|---|---|---|---|---|---|
| 100 | Steven | King | SKING | 515.123.4567 | 17-Jun-03 | AD_PRES | 24000 | – | – | 90 |
| 101 | Neena | Kochhar | NKOCHHAR | 515.123.4568 | 21-Sep-05 | AD_VP | 17000 | – | 100 | 90 |
| 102 | Lex | De Haan | LDEHAAN | 515.123.4569 | 13-Jan-01 | AD_VP | 17000 | – | 100 | 90 |
| 103 | Alexander | Hunold | AHUNOLD | 590.423.4567 | 3-Jan-06 | IT_PROG | 9000 | – | 102 | 60 |
| 104 | Bruce | Ernst | BERNST | 590.423.4568 | 21-May-07 | IT_PROG | 6000 | – | 103 | 60 |
| 105 | David | Austin | DAUSTIN | 590.423.4569 | 25-Jun-05 | IT_PROG | 4800 | – | 103 | 60 |
| 106 | Valli | Pataballa | VPATABAL | 590.423.4560 | 5-Feb-06 | IT_PROG | 4800 | – | 103 | 60 |
| 107 | Diana | Lorentz | DLORENTZ | 590.423.5567 | 7-Feb-07 | IT_PROG | 4200 | – | 103 | 60 |
| 108 | Nancy | Greenberg | NGREENBE | 515.124.4569 | 17-Aug-02 | FI_MGR | 12008 | – | 101 | 100 |
| 109 | Daniel | Faviet | DFAVIET | 515.124.4169 | 16-Aug-02 | FI_ACCOUNT | 9000 | – | 108 | 100 |
| 110 | John | Chen | JCHEN | 515.124.4269 | 28-Sep-05 | FI_ACCOUNT | 8200 | – | 108 | 100 |
| 111 | Ismael | Sciarra | ISCIARRA | 515.124.4369 | 30-Sep-05 | FI_ACCOUNT | 7700 | – | 108 | 100 |
| 112 | Jose Manuel | Urman | JMURMAN | 515.124.4469 | 7-Mar-06 | FI_ACCOUNT | 7800 | – | 108 | 100 |
| 113 | Luis | Popp | LPOPP | 515.124.4567 | 7-Dec-07 | FI_ACCOUNT | 6900 | – | 108 | 100 |
| 114 | Den | Raphaely | DRAPHEAL | 515.127.4561 | 7-Dec-02 | PU_MAN | 11000 | – | 100 | 30 |
| 115 | Alexander | Khoo | AKHOO | 515.127.4562 | 18-May-03 | PU_CLERK | 3100 | – | 114 | 30 |
| 116 | Shelli | Baida | SBAIDA | 515.127.4563 | 24-Dec-05 | PU_CLERK | 2900 | – | 114 | 30 |
| 117 | Sigal | Tobias | STOBIAS | 515.127.4564 | 24-Jul-05 | PU_CLERK | 2800 | – | 114 | 30 |
| 118 | Guy | Himuro | GHIMURO | 515.127.4565 | 15-Nov-06 | PU_CLERK | 2600 | – | 114 | 30 |
| 119 | Karen | Colmenares | KCOLMENA | 515.127.4566 | 10-Aug-07 | PU_CLERK | 2500 | – | 114 | 30 |
| 120 | Matthew | Weiss | MWEISS | 650.123.1234 | 18-Jul-04 | ST_MAN | 8000 | – | 100 | 50 |
| 121 | Adam | Fripp | AFRIPP | 650.123.2234 | 10-Apr-05 | ST_MAN | 8200 | – | 100 | 50 |
| 122 | Payam | Kaufling | PKAUFLIN | 650.123.3234 | 1-May-03 | ST_MAN | 7900 | – | 100 | 50 |
| 123 | Shanta | Vollman | SVOLLMAN | 650.123.4234 | 10-Oct-05 | ST_MAN | 6500 | – | 100 | 50 |
| 124 | Kevin | Mourgos | KMOURGOS | 650.123.5234 | 16-Nov-07 | ST_MAN | 5800 | – | 100 | 50 |
| 125 | Julia | Nayer | JNAYER | 650.124.1214 | 16-Jul-05 | ST_CLERK | 3200 | – | 120 | 50 |
| 126 | Irene | Mikkilineni | IMIKKILI | 650.124.1224 | 28-Sep-06 | ST_CLERK | 2700 | – | 120 | 50 |
| 127 | James | Landry | JLANDRY | 650.124.1334 | 14-Jan-07 | ST_CLERK | 2400 | – | 120 | 50 |
| 128 | Steven | Markle | SMARKLE | 650.124.1434 | 8-Mar-08 | ST_CLERK | 2200 | – | 120 | 50 |
| 129 | Laura | Bissot | LBISSOT | 650.124.5234 | 20-Aug-05 | ST_CLERK | 3300 | – | 121 | 50 |
| 130 | Mozhe | Atkinson | MATKINSO | 650.124.6234 | 30-Oct-05 | ST_CLERK | 2800 | – | 121 | 50 |
| 131 | James | Marlow | JAMRLOW | 650.124.7234 | 16-Feb-05 | ST_CLERK | 2500 | – | 121 | 50 |
| 132 | TJ | Olson | TJOLSON | 650.124.8234 | 10-Apr-07 | ST_CLERK | 2100 | – | 121 | 50 |
| 133 | Jason | Mallin | JMALLIN | 650.127.1934 | 14-Jun-04 | ST_CLERK | 3300 | – | 122 | 50 |
| 134 | Michael | Rogers | MROGERS | 650.127.1834 | 26-Aug-06 | ST_CLERK | 2900 | – | 122 | 50 |
| 135 | Ki | Gee | KGEE | 650.127.1734 | 12-Dec-07 | ST_CLERK | 2400 | – | 122 | 50 |
| 136 | Hazel | Philtanker | HPHILTAN | 650.127.1634 | 6-Feb-08 | ST_CLERK | 2200 | – | 122 | 50 |
| 137 | Renske | Ladwig | RLADWIG | 650.121.1234 | 14-Jul-03 | ST_CLERK | 3600 | – | 123 | 50 |
| 138 | Stephen | Stiles | SSTILES | 650.121.2034 | 26-Oct-05 | ST_CLERK | 3200 | – | 123 | 50 |
| 139 | John | Seo | JSEO | 650.121.2019 | 12-Feb-06 | ST_CLERK | 2700 | – | 123 | 50 |
| 140 | Joshua | Patel | JPATEL | 650.121.1834 | 6-Apr-06 | ST_CLERK | 2500 | – | 123 | 50 |
| 141 | Trenna | Rajs | TRAJS | 650.121.8009 | 17-Oct-03 | ST_CLERK | 3500 | – | 124 | 50 |
| 142 | Curtis | Davies | CDAVIES | 650.121.2994 | 29-Jan-05 | ST_CLERK | 3100 | – | 124 | 50 |
| 143 | Randall | Matos | RMATOS | 650.121.2874 | 15-Mar-06 | ST_CLERK | 2600 | – | 124 | 50 |
| 144 | Peter | Vargas | PVARGAS | 650.121.2004 | 9-Jul-06 | ST_CLERK | 2500 | – | 124 | 50 |
| 145 | John | Russell | JRUSSEL | 011.44.1344.429268 | 1-Oct-04 | SA_MAN | 14000 | 0.4 | 100 | 80 |
| 146 | Karen | Partners | KPARTNER | 011.44.1344.467268 | 5-Jan-05 | SA_MAN | 13500 | 0.3 | 100 | 80 |
| 147 | Alberto | Errazuriz | AERRAZUR | 011.44.1344.429278 | 10-Mar-05 | SA_MAN | 12000 | 0.3 | 100 | 80 |
| 148 | Gerald | Cambrault | GCAMBRAU | 011.44.1344.619268 | 15-Oct-07 | SA_MAN | 11000 | 0.3 | 100 | 80 |
| 149 | Eleni | Zlotkey | EZLOTKEY | 011.44.1344.429018 | 29-Jan-08 | SA_MAN | 10500 | 0.2 | 100 | 80 |
| 150 | Peter | Tucker | PTUCKER | 011.44.1344.129268 | 30-Jan-05 | SA_REP | 10000 | 0.3 | 145 | 80 |
| 151 | David | Bernstein | DBERNSTE | 011.44.1344.345268 | 24-Mar-05 | SA_REP | 9500 | 0.25 | 145 | 80 |
| 152 | Peter | Hall | PHALL | 011.44.1344.478968 | 20-Aug-05 | SA_REP | 9000 | 0.25 | 145 | 80 |
| 153 | Christopher | Olsen | COLSEN | 011.44.1344.498718 | 30-Mar-06 | SA_REP | 8000 | 0.2 | 145 | 80 |
| 154 | Nanette | Cambrault | NCAMBRAU | 011.44.1344.987668 | 9-Dec-06 | SA_REP | 7500 | 0.2 | 145 | 80 |
| 155 | Oliver | Tuvault | OTUVAULT | 011.44.1344.486508 | 23-Nov-07 | SA_REP | 7000 | 0.15 | 145 | 80 |
| 156 | Janette | King | JKING | 011.44.1345.429268 | 30-Jan-04 | SA_REP | 10000 | 0.35 | 146 | 80 |
| 157 | Patrick | Sully | PSULLY | 011.44.1345.929268 | 4-Mar-04 | SA_REP | 9500 | 0.35 | 146 | 80 |
| 158 | Allan | McEwen | AMCEWEN | 011.44.1345.829268 | 1-Aug-04 | SA_REP | 9000 | 0.35 | 146 | 80 |
| 159 | Lindsey | Smith | LSMITH | 011.44.1345.729268 | 10-Mar-05 | SA_REP | 8000 | 0.3 | 146 | 80 |
| 160 | Louise | Doran | LDORAN | 011.44.1345.629268 | 15-Dec-05 | SA_REP | 7500 | 0.3 | 146 | 80 |
| 161 | Sarath | Sewall | SSEWALL | 011.44.1345.529268 | 3-Nov-06 | SA_REP | 7000 | 0.25 | 146 | 80 |
| 162 | Clara | Vishney | CVISHNEY | 011.44.1346.129268 | 11-Nov-05 | SA_REP | 10500 | 0.25 | 147 | 80 |
| 163 | Danielle | Greene | DGREENE | 011.44.1346.229268 | 19-Mar-07 | SA_REP | 9500 | 0.15 | 147 | 80 |
| 164 | Mattea | Marvins | MMARVINS | 011.44.1346.329268 | 24-Jan-08 | SA_REP | 7200 | 0.1 | 147 | 80 |
| 165 | David | Lee | DLEE | 011.44.1346.529268 | 23-Feb-08 | SA_REP | 6800 | 0.1 | 147 | 80 |
| 166 | Sundar | Ande | SANDE | 011.44.1346.629268 | 24-Mar-08 | SA_REP | 6400 | 0.1 | 147 | 80 |
| 167 | Amit | Banda | ABANDA | 011.44.1346.729268 | 21-Apr-08 | SA_REP | 6200 | 0.1 | 147 | 80 |
| 168 | Lisa | Ozer | LOZER | 011.44.1343.929268 | 11-Mar-05 | SA_REP | 11500 | 0.25 | 148 | 80 |
| 169 | Harrison | Bloom | HBLOOM | 011.44.1343.829268 | 23-Mar-06 | SA_REP | 10000 | 0.2 | 148 | 80 |
| 170 | Tayler | Fox | TFOX | 011.44.1343.729268 | 24-Jan-06 | SA_REP | 9600 | 0.2 | 148 | 80 |
| 171 | William | Smith | WSMITH | 011.44.1343.629268 | 23-Feb-07 | SA_REP | 7400 | 0.15 | 148 | 80 |
| 172 | Elizabeth | Bates | EBATES | 011.44.1343.529268 | 24-Mar-07 | SA_REP | 7300 | 0.15 | 148 | 80 |
| 173 | Sundita | Kumar | SKUMAR | 011.44.1343.329268 | 21-Apr-08 | SA_REP | 6100 | 0.1 | 148 | 80 |
| 174 | Ellen | Abel | EABEL | 011.44.1644.429267 | 11-May-04 | SA_REP | 11000 | 0.3 | 149 | 80 |
| 175 | Alyssa | Hutton | AHUTTON | 011.44.1644.429266 | 19-Mar-05 | SA_REP | 8800 | 0.25 | 149 | 80 |
| 176 | Jonathon | Taylor | JTAYLOR | 011.44.1644.429265 | 24-Mar-06 | SA_REP | 8600 | 0.2 | 149 | 80 |
| 177 | Jack | Livingston | JLIVINGS | 011.44.1644.429264 | 23-Apr-06 | SA_REP | 8400 | 0.2 | 149 | 80 |
| 178 | Kimberely | Grant | KGRANT | 011.44.1644.429263 | 24-May-07 | SA_REP | 7000 | 0.15 | 149 | – |
| 179 | Charles | Johnson | CJOHNSON | 011.44.1644.429262 | 4-Jan-08 | SA_REP | 6200 | 0.1 | 149 | 80 |
| 180 | Winston | Taylor | WTAYLOR | 650.507.9876 | 24-Jan-06 | SH_CLERK | 3200 | – | 120 | 50 |
| 181 | Jean | Fleaur | JFLEAUR | 650.507.9877 | 23-Feb-06 | SH_CLERK | 3100 | – | 120 | 50 |
| 182 | Martha | Sullivan | MSULLIVA | 650.507.9878 | 21-Jun-07 | SH_CLERK | 2500 | – | 120 | 50 |
| 183 | Girard | Geoni | GGEONI | 650.507.9879 | 3-Feb-08 | SH_CLERK | 2800 | – | 120 | 50 |
| 184 | Nandita | Sarchand | NSARCHAN | 650.509.1876 | 27-Jan-04 | SH_CLERK | 4200 | – | 121 | 50 |
| 185 | Alexis | Bull | ABULL | 650.509.2876 | 20-Feb-05 | SH_CLERK | 4100 | – | 121 | 50 |
| 186 | Julia | Dellinger | JDELLING | 650.509.3876 | 24-Jun-06 | SH_CLERK | 3400 | – | 121 | 50 |
| 187 | Anthony | Cabrio | ACABRIO | 650.509.4876 | 7-Feb-07 | SH_CLERK | 3000 | – | 121 | 50 |
| 188 | Kelly | Chung | KCHUNG | 650.505.1876 | 14-Jun-05 | SH_CLERK | 3800 | – | 122 | 50 |
| 189 | Jennifer | Dilly | JDILLY | 650.505.2876 | 13-Aug-05 | SH_CLERK | 3600 | – | 122 | 50 |
| 190 | Timothy | Gates | TGATES | 650.505.3876 | 11-Jul-06 | SH_CLERK | 2900 | – | 122 | 50 |
| 191 | Randall | Perkins | RPERKINS | 650.505.4876 | 19-Dec-07 | SH_CLERK | 2500 | – | 122 | 50 |
| 192 | Sarah | Bell | SBELL | 650.501.1876 | 4-Feb-04 | SH_CLERK | 4000 | – | 123 | 50 |
| 193 | Britney | Everett | BEVERETT | 650.501.2876 | 3-Mar-05 | SH_CLERK | 3900 | – | 123 | 50 |
| 194 | Samuel | McCain | SMCCAIN | 650.501.3876 | 1-Jul-06 | SH_CLERK | 3200 | – | 123 | 50 |
| 195 | Vance | Jones | VJONES | 650.501.4876 | 17-Mar-07 | SH_CLERK | 2800 | – | 123 | 50 |
| 196 | Alana | Walsh | AWALSH | 650.507.9811 | 24-Apr-06 | SH_CLERK | 3100 | – | 124 | 50 |
| 197 | Kevin | Feeney | KFEENEY | 650.507.9822 | 23-May-06 | SH_CLERK | 3000 | – | 124 | 50 |
| 198 | Donald | OConnell | DOCONNEL | 650.507.9833 | 21-Jun-07 | SH_CLERK | 2600 | – | 124 | 50 |
| 199 | Douglas | Grant | DGRANT | 650.507.9844 | 13-Jan-08 | SH_CLERK | 2600 | – | 124 | 50 |
| 200 | Jennifer | Whalen | JWHALEN | 515.123.4444 | 17-Sep-03 | AD_ASST | 4400 | – | 101 | 10 |
| 201 | Michael | Hartstein | MHARTSTE | 515.123.5555 | 17-Feb-04 | MK_MAN | 13000 | – | 100 | 20 |
| 202 | Pat | Fay | PFAY | 603.123.6666 | 17-Aug-05 | MK_REP | 6000 | – | 201 | 20 |
| 203 | Susan | Mavris | SMAVRIS | 515.123.7777 | 7-Jun-02 | HR_REP | 6500 | – | 101 | 40 |
| 204 | Hermann | Baer | HBAER | 515.123.8888 | 7-Jun-02 | PR_REP | 10000 | – | 101 | 70 |
| 205 | Shelley | Higgins | SHIGGINS | 515.123.8080 | 7-Jun-02 | AC_MGR | 12008 | – | 101 | 110 |
| 206 | William | Gietz | WGIETZ | 515.123.8181 | 7-Jun-02 | AC_ACCOUNT | 8300 | – | 205 | 110 |
Like the first example on product category relationships, this manual process can be approached programmatically. See the code used to do so and the corresponding result set, below. For simplicity, only a subset of the preexisting columns or attributes are included for each employee and corresponding manager.
-- Retrieve each employee's and corresponding manager's information.
SELECT
hr.employees.employee_id,
hr.employees.first_name,
hr.employees.last_name,
hr.employees.salary AS salary,
manager.employee_id AS manager_id,
manager.first_name AS manager_first_name,
manager.last_name AS manager_last_name,
manager.salary AS manager_salary
FROM
hr.employees
LEFT JOIN
hr.employees manager
ON hr.employees.manager_id = manager.employee_id;
| employee_id | first_name | last_name | salary | manager_id | manager_first_name | manager_last_name | manager_salary |
|---|---|---|---|---|---|---|---|
| 101 | Neena | Kochhar | 17000 | 100 | Steven | King | 24000 |
| 102 | Lex | De Haan | 17000 | 100 | Steven | King | 24000 |
| 114 | Den | Raphaely | 11000 | 100 | Steven | King | 24000 |
| 120 | Matthew | Weiss | 8000 | 100 | Steven | King | 24000 |
| 121 | Adam | Fripp | 8200 | 100 | Steven | King | 24000 |
| 122 | Payam | Kaufling | 7900 | 100 | Steven | King | 24000 |
| 123 | Shanta | Vollman | 6500 | 100 | Steven | King | 24000 |
| 124 | Kevin | Mourgos | 5800 | 100 | Steven | King | 24000 |
| 145 | John | Russell | 14000 | 100 | Steven | King | 24000 |
| 146 | Karen | Partners | 13500 | 100 | Steven | King | 24000 |
| 147 | Alberto | Errazuriz | 12000 | 100 | Steven | King | 24000 |
| 148 | Gerald | Cambrault | 11000 | 100 | Steven | King | 24000 |
| 149 | Eleni | Zlotkey | 10500 | 100 | Steven | King | 24000 |
| 201 | Michael | Hartstein | 13000 | 100 | Steven | King | 24000 |
| 108 | Nancy | Greenberg | 12008 | 101 | Neena | Kochhar | 17000 |
| 200 | Jennifer | Whalen | 4400 | 101 | Neena | Kochhar | 17000 |
| 203 | Susan | Mavris | 6500 | 101 | Neena | Kochhar | 17000 |
| 204 | Hermann | Baer | 10000 | 101 | Neena | Kochhar | 17000 |
| 205 | Shelley | Higgins | 12008 | 101 | Neena | Kochhar | 17000 |
| 103 | Alexander | Hunold | 9000 | 102 | Lex | De Haan | 17000 |
| 104 | Bruce | Ernst | 6000 | 103 | Alexander | Hunold | 9000 |
| 105 | David | Austin | 4800 | 103 | Alexander | Hunold | 9000 |
| 106 | Valli | Pataballa | 4800 | 103 | Alexander | Hunold | 9000 |
| 107 | Diana | Lorentz | 4200 | 103 | Alexander | Hunold | 9000 |
| 109 | Daniel | Faviet | 9000 | 108 | Nancy | Greenberg | 12008 |
| 110 | John | Chen | 8200 | 108 | Nancy | Greenberg | 12008 |
| 111 | Ismael | Sciarra | 7700 | 108 | Nancy | Greenberg | 12008 |
| 112 | Jose Manuel | Urman | 7800 | 108 | Nancy | Greenberg | 12008 |
| 113 | Luis | Popp | 6900 | 108 | Nancy | Greenberg | 12008 |
| 115 | Alexander | Khoo | 3100 | 114 | Den | Raphaely | 11000 |
| 116 | Shelli | Baida | 2900 | 114 | Den | Raphaely | 11000 |
| 117 | Sigal | Tobias | 2800 | 114 | Den | Raphaely | 11000 |
| 118 | Guy | Himuro | 2600 | 114 | Den | Raphaely | 11000 |
| 119 | Karen | Colmenares | 2500 | 114 | Den | Raphaely | 11000 |
| 125 | Julia | Nayer | 3200 | 120 | Matthew | Weiss | 8000 |
| 126 | Irene | Mikkilineni | 2700 | 120 | Matthew | Weiss | 8000 |
| 127 | James | Landry | 2400 | 120 | Matthew | Weiss | 8000 |
| 128 | Steven | Markle | 2200 | 120 | Matthew | Weiss | 8000 |
| 180 | Winston | Taylor | 3200 | 120 | Matthew | Weiss | 8000 |
| 181 | Jean | Fleaur | 3100 | 120 | Matthew | Weiss | 8000 |
| 182 | Martha | Sullivan | 2500 | 120 | Matthew | Weiss | 8000 |
| 183 | Girard | Geoni | 2800 | 120 | Matthew | Weiss | 8000 |
| 129 | Laura | Bissot | 3300 | 121 | Adam | Fripp | 8200 |
| 130 | Mozhe | Atkinson | 2800 | 121 | Adam | Fripp | 8200 |
| 131 | James | Marlow | 2500 | 121 | Adam | Fripp | 8200 |
| 132 | TJ | Olson | 2100 | 121 | Adam | Fripp | 8200 |
| 184 | Nandita | Sarchand | 4200 | 121 | Adam | Fripp | 8200 |
| 185 | Alexis | Bull | 4100 | 121 | Adam | Fripp | 8200 |
| 186 | Julia | Dellinger | 3400 | 121 | Adam | Fripp | 8200 |
| 187 | Anthony | Cabrio | 3000 | 121 | Adam | Fripp | 8200 |
| 133 | Jason | Mallin | 3300 | 122 | Payam | Kaufling | 7900 |
| 134 | Michael | Rogers | 2900 | 122 | Payam | Kaufling | 7900 |
| 135 | Ki | Gee | 2400 | 122 | Payam | Kaufling | 7900 |
| 136 | Hazel | Philtanker | 2200 | 122 | Payam | Kaufling | 7900 |
| 188 | Kelly | Chung | 3800 | 122 | Payam | Kaufling | 7900 |
| 189 | Jennifer | Dilly | 3600 | 122 | Payam | Kaufling | 7900 |
| 190 | Timothy | Gates | 2900 | 122 | Payam | Kaufling | 7900 |
| 191 | Randall | Perkins | 2500 | 122 | Payam | Kaufling | 7900 |
| 137 | Renske | Ladwig | 3600 | 123 | Shanta | Vollman | 6500 |
| 138 | Stephen | Stiles | 3200 | 123 | Shanta | Vollman | 6500 |
| 139 | John | Seo | 2700 | 123 | Shanta | Vollman | 6500 |
| 140 | Joshua | Patel | 2500 | 123 | Shanta | Vollman | 6500 |
| 192 | Sarah | Bell | 4000 | 123 | Shanta | Vollman | 6500 |
| 193 | Britney | Everett | 3900 | 123 | Shanta | Vollman | 6500 |
| 194 | Samuel | McCain | 3200 | 123 | Shanta | Vollman | 6500 |
| 195 | Vance | Jones | 2800 | 123 | Shanta | Vollman | 6500 |
| 141 | Trenna | Rajs | 3500 | 124 | Kevin | Mourgos | 5800 |
| 142 | Curtis | Davies | 3100 | 124 | Kevin | Mourgos | 5800 |
| 143 | Randall | Matos | 2600 | 124 | Kevin | Mourgos | 5800 |
| 144 | Peter | Vargas | 2500 | 124 | Kevin | Mourgos | 5800 |
| 196 | Alana | Walsh | 3100 | 124 | Kevin | Mourgos | 5800 |
| 197 | Kevin | Feeney | 3000 | 124 | Kevin | Mourgos | 5800 |
| 198 | Donald | OConnell | 2600 | 124 | Kevin | Mourgos | 5800 |
| 199 | Douglas | Grant | 2600 | 124 | Kevin | Mourgos | 5800 |
| 150 | Peter | Tucker | 10000 | 145 | John | Russell | 14000 |
| 151 | David | Bernstein | 9500 | 145 | John | Russell | 14000 |
| 152 | Peter | Hall | 9000 | 145 | John | Russell | 14000 |
| 153 | Christopher | Olsen | 8000 | 145 | John | Russell | 14000 |
| 154 | Nanette | Cambrault | 7500 | 145 | John | Russell | 14000 |
| 155 | Oliver | Tuvault | 7000 | 145 | John | Russell | 14000 |
| 156 | Janette | King | 10000 | 146 | Karen | Partners | 13500 |
| 157 | Patrick | Sully | 9500 | 146 | Karen | Partners | 13500 |
| 158 | Allan | McEwen | 9000 | 146 | Karen | Partners | 13500 |
| 159 | Lindsey | Smith | 8000 | 146 | Karen | Partners | 13500 |
| 160 | Louise | Doran | 7500 | 146 | Karen | Partners | 13500 |
| 161 | Sarath | Sewall | 7000 | 146 | Karen | Partners | 13500 |
| 162 | Clara | Vishney | 10500 | 147 | Alberto | Errazuriz | 12000 |
| 163 | Danielle | Greene | 9500 | 147 | Alberto | Errazuriz | 12000 |
| 164 | Mattea | Marvins | 7200 | 147 | Alberto | Errazuriz | 12000 |
| 165 | David | Lee | 6800 | 147 | Alberto | Errazuriz | 12000 |
| 166 | Sundar | Ande | 6400 | 147 | Alberto | Errazuriz | 12000 |
| 167 | Amit | Banda | 6200 | 147 | Alberto | Errazuriz | 12000 |
| 168 | Lisa | Ozer | 11500 | 148 | Gerald | Cambrault | 11000 |
| 169 | Harrison | Bloom | 10000 | 148 | Gerald | Cambrault | 11000 |
| 170 | Tayler | Fox | 9600 | 148 | Gerald | Cambrault | 11000 |
| 171 | William | Smith | 7400 | 148 | Gerald | Cambrault | 11000 |
| 172 | Elizabeth | Bates | 7300 | 148 | Gerald | Cambrault | 11000 |
| 173 | Sundita | Kumar | 6100 | 148 | Gerald | Cambrault | 11000 |
| 174 | Ellen | Abel | 11000 | 149 | Eleni | Zlotkey | 10500 |
| 175 | Alyssa | Hutton | 8800 | 149 | Eleni | Zlotkey | 10500 |
| 176 | Jonathon | Taylor | 8600 | 149 | Eleni | Zlotkey | 10500 |
| 177 | Jack | Livingston | 8400 | 149 | Eleni | Zlotkey | 10500 |
| 178 | Kimberely | Grant | 7000 | 149 | Eleni | Zlotkey | 10500 |
| 179 | Charles | Johnson | 6200 | 149 | Eleni | Zlotkey | 10500 |
| 202 | Pat | Fay | 6000 | 201 | Michael | Hartstein | 13000 |
| 206 | William | Gietz | 8300 | 205 | Shelley | Higgins | 12008 |
| 100 | Steven | King | 24000 | – | – | – | – |
Step-rate Mortgages
A step-rate mortgage is one where the interest rate increases in a series of steps over time and for a specific duration. These steps and corresponding details are often conveyed in a schedule or step-rate addendum. In the table below, there exists a handful of mortgage loan account numbers and the associated step rate addendum data. There is one row per account number and step number. All data is fictional.
| acct_num | step_num | int_rate | pi_amt |
|---|---|---|---|
| 6358218216 | 1 | 2 | 1000 |
| 6358218216 | 2 | 2.125 | 1125 |
| 6358218216 | 3 | 2.3250000000000002 | 1325 |
| 6358218216 | 4 | 2.75 | 1425 |
| 4585365392 | 1 | 3 | 2000 |
| 4585365392 | 2 | 3.125 | 2125 |
| 4585365392 | 3 | 3.25 | 2325 |
| 4585365392 | 4 | 3.75 | 2425 |
| 4585365392 | 5 | 3.7749999999999999 | 2500 |
| 4807137888 | 1 | 4.25 | 1300 |
| 4807137888 | 2 | 4.3250000000000002 | 1345 |
| 4807137888 | 3 | 4.3499999999999996 | 1375 |
| 4807137888 | 4 | 4.45 | 1400 |
| 8016806206 | 1 | 2.25 | 1200 |
| 8016806206 | 2 | 2.625 | 1350 |
| 8016806206 | 3 | 2.75 | 1425 |
Now, imagine you’re given the following task: for each account and step number, compare the current step’s data with the next step’s data by displaying both steps’ data in a single row. In addition, provide the amount the principal and interest increased from step to step based on the comparison of principal and interest amounts for the steps. That is, compute the difference between the next step’s principal and interest amount and the current step’s principal and interest amount. Again, your solution should contain the step’s data and the subsequent step’s data, if one exists, in a single row for quick comparison.
Unlike the first two examples where a relationship between two rows was explicitly captured in a single row (e.g., an employee ID and corresponding manager ID), here the relationship between two or more rows is implied by the step numbers. Each account’s step numbers are sequential, one followed by two, two followed by three, and so forth. This fact can be relied upon when developing a solution to the task. Specifically, it can be added to the ON clause to ensure the necessary step comparisons are made by stitching together the appropriate rows (e.g., 1 compared to 2, 2 compared to 3, etc.). The first condition necessary in the ON clause is straightforward. The comparisons need to be made using step data from the same account number. The second and not so common condition is the step number in the current row is equal to the next step number less one. When attempting to make sense of the second condition, it’s important to remember two instances of the same table are being used.
One possible solution and corresponding result set can be found below. Keep in mind, with the advent of window or analytic functions, this problem can be solved in an arguably more intuitive manner. Row reference functions are not the focus of this page; however, an alternative solution utilizing them can be found below the initial solution.
-- Using LEFT JOIN to solve.
SELECT
current_step.acct_num,
current_step.step_num AS current_step_num,
current_step.int_rate AS current_int_rate,
current_step.pi_amt AS current_pi_amt,
next_step.step_num AS next_step_num,
next_step.int_rate AS next_int_rate,
next_step.pi_amt AS next_pi_amt,
next_step.pi_amt - current_step.pi_amt AS amt_increase
FROM
pi_loan current_step
LEFT JOIN
pi_loan next_step
ON current_step.acct_num = next_step.acct_num
AND current_step.step_num = (next_step.step_num - 1)
ORDER BY
current_step.acct_num, current_step.step_num;
-- Using Window/analytic function to solve.
SELECT
pi_loan.acct_num,
pi_loan.step_num AS current_step_num,
pi_loan.int_rate AS current_int_rate,
pi_loan.pi_amt AS current_pi_amt,
LEAD(pi_loan.step_num, 1, NULL) OVER(
PARTITION BY pi_loan.acct_num
ORDER BY pi_loan.step_num
) AS next_step_num,
LEAD(pi_loan.int_rate, 1, NULL) OVER(
PARTITION BY pi_loan.acct_num
ORDER BY pi_loan.step_num
) AS next_int_rate,
LEAD(pi_loan.pi_amt, 1, NULL) OVER(
PARTITION BY pi_loan.acct_num
ORDER BY pi_loan.step_num
) AS next_pi_amt,
(
LEAD(pi_loan.pi_amt, 1, NULL) OVER(
PARTITION BY pi_loan.acct_num
ORDER BY pi_loan.step_num
)
- pi_loan.pi_amt
) AS amt_increase
FROM
pi_loan
ORDER BY
pi_loan.acct_num,
pi_loan.step_num;
| acct_num | current_step_num | current_int_rate | current_pi_amt | next_step_num | next_int_rate | next_pi_amt | amt_increase |
|---|---|---|---|---|---|---|---|
| 4585365392 | 1 | 3 | 2000 | 2 | 3.125 | 2125 | 125 |
| 4585365392 | 2 | 3.125 | 2125 | 3 | 3.25 | 2325 | 200 |
| 4585365392 | 3 | 3.25 | 2325 | 4 | 3.75 | 2425 | 100 |
| 4585365392 | 4 | 3.75 | 2425 | 5 | 3.775 | 2500 | 75 |
| 4585365392 | 5 | 3.775 | 2500 | – | – | – | – |
| 4807137888 | 1 | 4.25 | 1300 | 2 | 4.325 | 1345 | 45 |
| 4807137888 | 2 | 4.325 | 1345 | 3 | 4.35 | 1375 | 30 |
| 4807137888 | 3 | 4.35 | 1375 | 4 | 4.45 | 1400 | 25 |
| 4807137888 | 4 | 4.45 | 1400 | – | – | – | – |
| 6358218216 | 1 | 2 | 1000 | 2 | 2.125 | 1125 | 125 |
| 6358218216 | 2 | 2.125 | 1125 | 3 | 2.325 | 1325 | 200 |
| 6358218216 | 3 | 2.325 | 1325 | 4 | 2.75 | 1425 | 100 |
| 6358218216 | 4 | 2.75 | 1425 | – | – | – | – |
| 8016806206 | 1 | 2.25 | 1200 | 2 | 2.625 | 1350 | 150 |
| 8016806206 | 2 | 2.625 | 1350 | 3 | 2.75 | 1425 | 75 |
| 8016806206 | 3 | 2.75 | 1425 | – | – | – | – |
The SELF JOIN has a special place in my heart due to the initial difficulty I felt when attempting to understand it. In the beginning, the ON clause simply didn’t click for me. Hopefully, as a result of reading this, you are able to avoid the headache I endured or at least minimize the headache’s duration.
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.