5th Sep 2023 23 minutes read SQL Joins: 12 Practice Questions with Detailed Answers Tihomir Babic JOIN sql practice Table of Contents List of Exercises INNER JOIN Dataset 1 Exercise 1: List All Books and Their Authors Exercise 2: List Authors and Books Published After 2005 Exercise 3: Show Books Adapted Within 4 Years and Rated Lower Than the Adaptation LEFT JOIN Exercise 4: Show All Books and Their Adaptations (If Any) Exercise 5: Show All Books and Their Movie Adaptations RIGHT JOIN Exercise 6: Show All Books with Their Reviews (If Any) FULL JOIN Exercise 7: List All the Books and All the Authors Joining 3 or More Tables Dataset 2 Exercise 8: Show Products Under 150 Calories and Their Department Exercise 9: List All Products with Their Producers, Departments, and Carbs Exercise 10: Show All the Products, Prices, Producers, and Departments Self-Join Dataset 3 Exercise 11: List All Workers and Their Direct Supervisors Non-Equi Joins Dataset 4 Exercise 12: Show Cars with Higher Mileage Than a Specific Car SQL JOINs Practice Makes Perfect. More Practice? Perfect-er! In this article, we dig into our SQL JOINS course and give you 12 join exercises to solve. But don’t worry – all the exercises have solutions and explanations. If you get stuck, help is there! This is, after all, made for practicing and learning. SQL joins can be tricky. It’s not just the syntax, but also knowing what joins to use in what scenarios. Joins are used when combining data from two or more tables in SQL. The tables can be joined in several ways, and, depending on the tables, each way of joining them can result in a completely different result. There’s no other way to learn this than practice. Yes, you can read explanations and typical uses of SQL joins. That helps, for sure! But practice builds on that through problem-solving and repetition, which makes your knowledge stick. The more you practice, the greater the possibility that the real-life data problems you’ll have to solve will be similar or completely the same as what you’ve already done! And practice is what we’ll do in this article! We’ll show you exercises for basic and more advanced SQL joins uses. If you like them, you’ll enjoy our SQL JOINs course even more, as all the exercises are taken from there. In total, the course offers you 93 SQL joins exercises. They cover topics ranging from the types of joins in SQL, to filtering data, joining more than two tables, self-joining a table, and using non-equi joins. OK, so let’s introduce the datasets and start exercising, shall we? Feel free to help yourself with the SQL JOIN Cheat Sheet as you go. List of Exercises Here's a list of all exercises in the article: Exercise 1: List All Books and Their Authors Exercise 2: List Authors and Books Published After 2005 Exercise 3: Show Books Adapted Within 4 Years and Rated Lower Than the Adaptation Exercise 4: Show All Books and Their Adaptations (If Any) Exercise 5: Show All Books and Their Movie Adaptations Exercise 6: Show All Books with Their Reviews (If Any) Exercise 7: List All the Books and All the Authors Exercise 8: Show Products Under 150 Calories and Their Department Exercise 9: List All Products with Their Producers, Departments, and Carbs Exercise 10: Show All the Products, Prices, Producers, and Departments Exercise 11: List All Workers and Their Direct Supervisors Exercise 12: Show Cars with Higher Mileage Than a Specific Car INNER JOIN INNER JOIN is a type of SQL join that returns only the matching rows from the joined tables. To show you how this works, we’ll use Dataset 1 from the course. Dataset 1 The dataset consists of four tables: author, book, adaptation, and book_review. The first table shows the author data in the following columns: id – The author’s unique ID within the database. name – The author’s name. birth_year – The year when that author was born. death_year – The year when that author died (the field is empty if they are still alive). Here are the table’s first few rows: idnamebirth_yeardeath_year 1Marcella Cole1983NULL 2Lisa Mullins18911950 3Dennis Stokes19351994 4Randolph Vasquez19572004 5Daniel Branson19651990 ………… The second table, book, shows details about books. The columns are: id – The ID of a given book. author_id – The ID of the author who wrote that book. title – The book’s title. publish_year – The year when the book was published. publishing_house – The name of the publishing house that printed the book. rating – The average rating for the book. These are the first five rows: idauthor_idtitlepublish_yearpublishing_houserating 1NULLSoulless girl2008Golden Albatros4.3 2NULLWeak Heart1980Diarmud Inc.3.8 34Faith Of Light1995White Cloud Press4.3 4NULLMemory Of Hope2000Rutis Enterprises2.7 56Warrior Of Wind2005Maverick4.6 ……………… The adaptation table has the following columns: book_id – The ID of the adapted book. type – The type of adaptation (e.g. movie, game, play, musical). title – The name of this adaptation. release_year – The year when the adaptation was created. rating – The average rating for the adaptation. Here’s a snapshot of the data from this table: book_idtypetitlerelease_yearrating 1movieGone With The Wolves: The Beginning20083 3movieCompanions Of Tomorrow20014.2 5movieHomeless Warrior20084 2movieBlacksmith With Silver20144.3 4moviePatrons And Bearers20043.2 …………… The final table is book_review. It consists of the following columns: book_id - The ID of a reviewed book. review - The summary of the review. author - The name of the review's author. Here’s the data: book_idreviewauthor 1An incredible bookSylvia Jones 1Great, although it has some flawsJessica Parker 2Dennis Stokes takes the reader for a ride full of emotionsThomas Green 3Incredible craftsmanship of the authorMartin Freeman 4Not the best book by this authorJude Falth 5Claudia Johnson at her best!Joe Marqiz 6I cannot recall more captivating plotAlexander Durham Exercise 1: List All Books and Their Authors Exercise: Show the name of each author together with the title of the book they wrote and the year in which that book was published. Solution: SELECT name, title, publish_year FROM author JOIN book ON author.id = book.author_id; Solution explanation: The query selects the name of the author, the book title, and its publishing year. This is data from the two tables: author and book. We are able to access both tables by using INNER JOIN. It returns only rows with matching values (values that satisfy the join condition) from both tables. We first reference the table author in the FROM clause. Then we add the JOIN clause (which can also be written as INNER JOIN in SQL) and reference the table book. The tables are joined on the common column. In this case, it's id from the table author and author_id from the table book. We want to join the rows where these columns share the same value. We do that using the ON clause and specifying the column names. We also put the table name before each column so the database knows where to look. That’s primarily because there’s an id column in both tables, but we want the id column only from the author table. By referencing the table name, the database will know from which table we need that column. Solution output: Here’s the output snapshot. We got all this data by joining two tables: nametitlepublish_year Marcella ColeGone With The Wolves2005 Lisa MullinsCompanions And Officers1930 Dennis StokesBlacksmith With Silver1984 Randolph VasquezFaith Of Light1995 Michael RostkovskyWarrior Of Wind2005 ……… Exercise 2: List Authors and Books Published After 2005 Exercise: Show the name of each author together with the title of the book they wrote and the year in which that book was published. Show only books published after 2005. Solution: SELECT name, title, publish_year FROM author JOIN book ON author.id = book.author_id WHERE publish_year > 2005; Solution explanation: This exercise and its solution are almost the same as the previous one. This is reflected by the query selecting the same columns and joining the tables in the same way as earlier. The difference is that the exercise now asks us to show only books published after 2005. This requires filtering the output; we do that using the WHERE clause. WHERE is a clause that accepts conditions used to filter out the data. It is written after joining the tables. In our example, we filter by referencing the column publish_year after WHERE and using the comparison operator ‘greater than’ (>) to find the years after 2005. Solution output: The output shows only one book published after 2005. nametitlepublish_year Darlene LyonsTemptations In Nature2007 Exercise 3: Show Books Adapted Within 4 Years and Rated Lower Than the Adaptation Exercise: For each book, show its title, adaptation title, adaptation year, and publication year. Include only books with a rating lower than the rating of their corresponding adaptation. Additionally, show only those books for which an adaptation was released within four years of the book’s publication. Rename the title column from the book table to book_title and the title column from the adaptation table to adaptation_title. Solution: SELECT book.title AS book_title, adaptation.title AS adaptation_title, book.publish_year, adaptation.release_year FROM book JOIN adaptation ON book.id = adaptation.book_id WHERE adaptation.release_year - book.publish_year <= 4 AND book.rating < adaptation.rating; Solution explanation: Let’s start explaining the solution from the FROM and JOIN clauses. The columns we need to show are from the tables book and adaptation. We reference the first table in FROM and the second in JOIN. In the ON clause, we equal the two book ID columns and specify the table of each column. This is the same as earlier, only with different table and column names. Now, we need to select the required columns. The thing here is there’s a title column in both tables. To avoid ambiguity, a best practice is to reference the table name before each column in the SELECT. Note: The above is mandatory only for ambiguous columns. However, it’s a good idea to do that with all columns; it improves code readability and the approach remains consistent. After selecting the columns, we need to rename some of them. We do that using the keyword AS and writing a new column name afterward. That way, one title column becomes book_title, the other becomes adaptation_title. Giving aliases to the column names also helps get rid of ambiguity. Now we need to filter the output. The first condition is that the adaptation had to be released four years or less after the book. We again use WHERE and simply deduct the book publish year from the adaptation release year. Then we say that the difference has to be less than or equal to (<=) 4. We also need to add the second condition, where the book has a lower rating than the adaptation. It’s simple! The question implies that both the first and the second conditions have to be satisfied. The clue is in AND, a logical operator we use for adding the second condition. Here, it uses the ‘less than’ (<) operator to compare the two ratings. Solution output: The output shows three book–adaptation pairs that satisfy the conditions. book_titleadaptation_titlepublish_yearrelease_year Memory Of HopePatrons And Bearers20002004 Music At The LakeMusic At The Lake20042007 Companion Of TomorrowLighting Faith19491952 LEFT JOIN Now that you get the gist of INNER JOIN, let’s move on to LEFT JOIN. It’s a type of outer join that returns all the columns from the left (the first) table and only the matching rows from the right (the second) table. If there is non-matching data, it’s shown as NULL. You can learn more in our article about LEFT JOIN. Exercise 4: Show All Books and Their Adaptations (If Any) Exercise: Show the title of each book together with the title of its adaptation and the date of the release. Show all books, regardless of whether they had adaptations. Solution: SELECT book.title, adaptation.title, adaptation.release_year FROM book LEFT JOIN adaptation ON book.id = adaptation.book_id; Solution explanation: We first select the required columns from the two tables. Then we join book (the left table) with adaptation (the right table) using LEFT JOIN. You see that the SQL join syntax is the same for INNER JOIN. The only thing that changes is the join keyword. Note: SQL accepts both LEFT JOIN and LEFT OUTER JOIN. They are the same command. Solution output: The output snapshot shows the required data, with some of the data shown as NULL. These are the books without the adaptation. titletitle-2release_year Soulless girlGone With The Wolves: The Beginning2008 Faith Of LightCompanions Of Tomorrow2001 Warrior Of WindHomeless Warrior2008 ……… Guarding The EmperorNULLNULL Blacksmith With SilverNULLNULL ……… Exercise 5: Show All Books and Their Movie Adaptations Exercise: Show all books with their movie adaptations. Select each book's title, the name of its publishing house, the title of its adaptation, and the type of the adaptation. Keep the books with no adaptations in the result. Solution: SELECT book.title, publishing_house, adaptation.title, adaptation.type FROM book LEFT JOIN adaptation ON book.id = adaptation.book_id WHERE type = 'movie' OR type IS NULL; Solution explanation: The question asks to show all the rows, even those without any adaptations. It’s possible that there are books without adaptations, so we use LEFT JOIN. We first select the book title, its publishing house, its adaptation title, and its type. Then we join book (the left table) with adaptation (the right table) using LEFT JOIN. We join the tables on the book ID. All the books that don’t satisfy the conditions will have NULLs as an adaptation title and type. We filter data using WHERE. The first condition is that the adaptation type has to be a movie, so we equal the type column with a movie using the equal sign (=). Note: When using text data in the WHERE condition, it must be enclosed in single quotes (''). The second filtering condition is added using the logical operator OR. It says that the type can also be NULL if it’s not a movie. The exercise asks us to keep books with no adaptations in the results. Solution output: Here’s the output snapshot. You can see that it shows only books adapted as movies or not adapted at all. titlepublishing_housetitle-2type Soulless girlGolden AlbatrosGone With The Wolves: The Beginningmovie Faith Of LightWhite Cloud PressCompanions Of Tomorrowmovie Warrior Of WindMaverickHomeless Warriormovie ………… Guarding The EmperorFlying Pen MediaNULLNULL Blacksmith With SilverDiarmud Inc.NULLNULL RIGHT JOIN Where there’s LEFT JOIN, there’s also RIGHT JOIN, right? Despite being the LEFT JOIN's mirror image, it’s still a part of the SQL joins practice. It’s a type of join that returns all the columns from the right (the second) table and only the matching rows from the left (the first) table. If there is non-matching data, it’s shown as NULL. Exercise 6: Show All Books with Their Reviews (If Any) Exercise: Join the book_review and book tables using a RIGHT JOIN. Show the title of the book, the corresponding review, and the name of the review's author. Consider all books, even those that weren't reviewed. Solution: SELECT book.title, book_review.review, book_review.author FROM book_review RIGHT JOIN book ON book.id = book_review.book_id; Solution explanation: We first select the required columns. Then we do as we’re told: join the tables using RIGHT JOIN. We join the tables on the book ID. The table book is the right table; we want all the data from it, regardless of the reviews. As you can see, the syntax stays the same as in INNER JOIN and LEFT JOIN. Note: SQL accepts both RIGHT JOIN and RIGHT OUTER JOIN. Solution output: The query returns all the book titles, their reviews, and authors. Where there’s no review or author information, a NULL is shown. titlereviewauthor Soulless girlAn incredible bookSylvia Jones Soulless girlGreat, although it has some flawsJessica Parker ……… Guarding The EmperorNULLNULL Companions And OfficersNULLNULL Blacksmith With SilverNULLNULL ……… FULL JOIN Here’s another join type that’s useful in some scenarios: the FULL JOIN . This is a LEFT JOIN and RIGHT JOIN put together. It shows matching rows from both tables, rows that have no match from the left table, and rows that have no match from the right table. In short, it shows all data from both tables. You can read more about how and when to use FULL JOIN. Exercise 7: List All the Books and All the Authors Exercise: Display the title of each book along with the name of its author. Show all books, even those without an author. Show all authors, even those who haven't published a book yet. Use a FULL JOIN. Solution: SELECT title, name FROM book FULL JOIN author ON book.author_id = author.id; Solution explanation: The question requires showing all books, but also all authors – FULL JOIN is perfect for doing this elegantly. We select the book title and the author's name. Next, we FULL JOIN the table book with the table author. The joining condition is that the author ID has to be the same in both tables. Again, the syntax is the same as in all the previous join types. Note: SQL accepts both FULL JOIN and FULL OUTER JOIN. Solution output: The output shows all the books and all the authors, whether the authors or books exist in both tables or not. titlename Gone With The WolvesMarcella Cole Companions And OfficersLisa Mullins …… NULLDaniel Branson …… Weep Of The WestNULL Joining 3 or More Tables Yes, SQL joins allow for joining more than two tables. We’ll see how to do that in this part of the SQL joins practice. You can find a more detailed explanation of multiple joins here. We also need a new dataset, so let’s introduce it. Dataset 2 The first table in the dataset is department. Its columns are: id – The unique ID of the department. name – The department name, i.e. where a particular type of product is sold. Here’s the data from the table. idname 1fruits 2vegetables 3seafood 4deli 5bakery 6meat 7dairy The second table is product, and it consists of the following columns: id – The ID of a given product. name – The product’s name. department_id – The ID of the department where the product is located. shelf_id – The ID of the shelf of that department where the product is located. producer_id – The ID of the company that manufactures this product. price – The product’s price. Here’s the data snapshot: idnamedepartment_idshelf_idproducer_idprice 1Apple11NULL0.5 2Avocado1171 3Banana1170.5 4GrapefruitNULL110.5 5Grapes1142 ……………… The next table is nutrition_data. Its columns and data are given below: product_id – The ID of a product. calories – The calorific value of that product. fat – The amount of fat in that product. carbohydrate – The amount of carbohydrates in that product. protein – The amount of protein in that product. product_idcaloriesfatcarbohydrateprotein 1130051 2504.531 31100301 4600151 NULL900230 …………… The fourth table is named producer. It has the following columns: id – The ID of a given food producer. name – The name of the producer. Below is the data from this table: idname 1BeHealthy 2HealthyFood Inc. 3SupremeFoods 4Foodie 5Gusto 6Baker n Sons 7GoodFoods 8Tasty n Healthy The last table in the dataset is sales_history. It has the following columns: date – The date of sale. product_id – The ID of the product sold. amount – The amount of that product sold on a particular day. Here’s the data, too: dateproduct_idamount 2015-01-14114 2015-01-14113 2015-01-1522 2015-01-1626 2015-01-1738 ……… Exercise 8: Show Products Under 150 Calories and Their Department Exercise: List all products that have fewer than 150 calories. For each product, show its name (rename the column product) and the name of the department where it can be found (name the column department). Solution: SELECT p.name AS product, d.name AS department FROM department d JOIN product p ON d.id = p.department_id JOIN nutrition_data nd ON nd.product_id = p.id WHERE nd.calories < 150; Solution explanation: The general principle of how you join the third (fourth, fifth…) table is that you simply add another JOIN. You can see how it’s done in this article explaining multiple joins. We’ll do it the same way here. We first join the department table with the product table on the department ID using JOIN. But we also need the third table. To get the data from it, we just add another JOIN, which will join the product table with the nutrition_data table. The syntax is the same as with the first join. In this case, the query joins the tables on the product ID. Then we use WHERE to find products with fewer than 150 calories. We finally select the product and department names and rename the columns as per the exercise instructions. Note: You probably noticed both selected columns have the same original name. And you also noticed we solved this ambiguity by putting some strange short table names in front of all the columns in the query. These shortened names are table aliases, which you give by simply writing them after the table name in FROM or JOIN. By giving aliases to the tables, you can shorten the tables’ names. Therefore, you don’t have to write their full names (sometimes they can be really long!), but the short aliases instead. This saves time and space. Solution output: The output shows a list of the products and the department they belong to. It includes only those products with fewer than 150 calories. productdepartment Applefruits Avocadofruits Bananafruits Kiwifruits Lemonfruits …… Exercise 9: List All Products with Their Producers, Departments, and Carbs Exercise: For each product, display the: Name of the company that produced it (name the column producer_name). Name of the department where the product is located (name it department_name). Product name (name it product_name). Total number of carbohydrates in the product. Your query should still consider products with no information about producer_id or department_id. Solution: SELECT prod.name AS producer_name, d.name AS department_name, p.name AS product_name, nd.carbohydrate FROM product p LEFT JOIN producer prod ON prod.id = p.producer_id LEFT JOIN department d ON d.id = p.department_id LEFT JOIN nutrition_data nd ON nd.product_id = p.id; Solution explanation: The query selects the required columns. Then it joins the table product with the table producer on the producer ID using LEFT JOIN. We choose this type of join because we have to include products without producer data. Then we add another LEFT JOIN. This one adds the department table and joins it with the product table. Again, we choose LEFT JOIN because we need to show products that don’t have a department. There’s also a third join! We simply add it to the chain of the previous joins. It’s again LEFT JOIN, as we add the nutrition_data table and join it with the product table. This is an interesting topic to explore, so here’s an article that explains multiple LEFT JOINs to help you with it. Solution output: The output shows all the products with their producer and department names and carbohydrate amounts: producer_namedepartment_nameproduct_namecarbohydrate BeHealthyfruitsKiwi20 BeHealthyvegetablesBroccoli8 BeHealthymeatChickenNULL BeHealthyNULLGrapefruit15 HealthyFood Inc.vegetablesCelery4 ………… If you need more details, please read how to LEFT JOIN multiple tables in SQL. Exercise 10: Show All the Products, Prices, Producers, and Departments Exercise: For each product, show its name, price, producer name, and department name. Alias the columns as product_name, product_price, producer_name, and department_name, respectively. Include all the products, even those without a producer or department. Also, include the producers and departments without a product. Solution: SELECT p.name AS product_name, p.price AS product_price, prod.name AS producer_name, d.name AS department_name FROM product p FULL JOIN producer prod ON p.producer_id = prod.id FULL JOIN department d ON d.id = p.department_id; Solution explanation: This exercise requires using FULL JOIN, as we need all the data from the tables we’ll use: product, producer, and department. The syntax is the same as in the previous examples. We just join the different tables (product and producer) on the producer ID and use a different type of join: FULL JOIN. The second FULL JOIN joins the product table with the department table. After selecting the required columns and renaming them, we get the following output. Solution output: The solution shows all the data from the selected tables and columns: product_nameproduct_priceproducer_namedepartment_name Chicken5.5BeHealthymeat Broccoli2.5BeHealthyvegetables Kiwi0.3BeHealthyfruits Grapefruit0.5BeHealthyNULL Cucumber0.7HealthyFood Inc.vegetables ………… Self-Join A self-join is not a distinct type of SQL JOIN – any join can be used for self-joining a table. It’s simply a join used to join the table with itself. By giving different aliases to the same table, it’s treated as two different tables when self-joined. For more details, check out our illustrated guide to the SQL self-join. Dataset 3 The dataset for this example consists of only one table: workshop_workers. It has the following columns. id – The worker’s ID. name – The worker’s first and last name. specialization – The worker's specialization. master_id – The ID of the worker's supervisor. experience – The worker's years of experience. project_id – The ID of the project to which the worker is currently assigned. Here’s the data: idnamespecializationmaster_idexperienceproject_id 1Mathew ConnwoodworkingNULL201 2Kate Brownwoodworking141 3John Doeincrusting531 4John Kowalskywatchmaking723 5Suzan GregowitchincrustingNULL154 Exercise 11: List All Workers and Their Direct Supervisors Exercise: Show all workers' names together with the names of their direct supervisors. Rename the columns apprentice_name and master_name, respectively. Consider only workers who have a supervisor (i.e. a master). Solution: SELECT apprentice.name AS apprentice_name, master.name AS master_name FROM workshop_workers apprentice JOIN workshop_workers master ON apprentice.master_id = master.id; Solution explanation: Let’s start with explaining the self-join. The general principle is the same as with regular joins. We reference the table in FROM and give it an alias, apprentice. Then we use JOIN and reference the same table in it. This time, we give the table the alias master. We’re basically pretending that one table has the apprentice data and the other has the master data. The tables are joined on the master ID from the apprentice table and the ID from the master table. This example is a typical use of a self-join: the table has a column (master_id) that references another column from the same table (id). Both columns show the worker’s ID. When there’s NULL in master_id, it means that the worker doesn’t have a master. In other words, they are the master. After self-joining, we simply select the required columns and rename them. Solution output: The output shows all the apprentices and their direct supervisors. apprentice_namemaster_name Kate BrownMathew Conn John DoeSuzan Gregowitch John KowalskyJoe Darrington Peter ParkerJoe Darrington Mary SmithMathew Conn Carlos BellSuzan Gregowitch Dennis WrightJoe Darrington Non-Equi Joins The final topic we’ll tackle in this SQL joins practice are non-equi joins. The joins we used so far are called equi-joins because they use the equality sign (=) in the joining condition. Non-equi are all other joins that use any other operators – comparison operators (<, >, <=, >=, !=, <>), the BETWEEN operator, or any other logical condition – to join tables. Dataset 4 We’ll use the dataset consisting of two tables. The first table is car. Here are its columns: id – The car’s ID in the database. model – The car’s model. brand – The car’s brand. original_price – The original price of that car when new. mileage – The car’s total mileage. prod_year – The car’s production year. The data looks like this: idmodelbrandoriginal_pricemileageprod_year 1SpeedsterTeiko80,000150,0001999 2RoadmasterTeiko110,00030,0001980 3SundryTeiko40,00025,0001991 4FuruDomus50,00010,0002002 5EmperorDomus65,000140,0002005 6KingDomus200,0006,0001981 7EmpressDomus60,0007,6001997 8FuryTatsu150,00013,0001993 The second table is charity_auction with these columns: car_id – The car’s ID. initial_price – The car’s initial (i.e. starting) price. final_price – The actual price when the car was sold. buyer_id – The ID of the person who bought the car. Here’s the data: car_idinitial_pricefinal_pricebuyer_id 165,000NULLNULL 335,00050,0001 550,000120,0003 6350,000410,0004 765,000NULLNULL Exercise 12: Show Cars with Higher Mileage Than a Specific Car Exercise: Show the model, brand, and final price of each car sold at the auction. Consider only those sold cars that have more mileage than the car with the id = 4. Solution: SELECT car.model, car.brand, car.final_price FROM car JOIN charity_auction ca ON car.id = ca.car_id JOIN car car2 ON car.mileage > car2.mileage WHERE car2.id = 4 AND final_price IS NOT NULL; Solution explanation: We select the car model, brand, and final price. In the first JOIN, we join the car table with the charity_auction table. The tables are joined where the car IDs are the same. This is our regular equi JOIN. We add the second JOIN, which is a self-join. It adds the table car again, so we can filter the data using the non-equi join condition. The condition will return all the cars from the car table and all the cars from the car2 table with the lower mileage. This is a non-equi condition as it uses the ‘greater than’ ( > ) operator. The syntax is the same, but there’s > instead of = this time. Finally, we need to filter data using WHERE. We’re not interested in comparing the mileage of all cars. We want to show the cars that have a mileage higher than the car with id = 4. This is what the first filtering condition does. We add another filtering condition that says the final price shouldn’t be NULL, i.e., the car has to have been sold in the auction. Solution output: The result shows two cars: modelbrandfinal_price SundryTeiko50,000 EmperorDomus120,000 SQL JOINs Practice Makes Perfect. More Practice? Perfect-er! Twelve SQL join exercises is a solid amount of practice. Through these exercises, you could learn and practice all the most common join topics that trouble beginner and intermediate users. Now, you just need to keep going! When you practice even more, you become even perfect-er. So if you liked our exercises, you can get more of the same in our SQL JOINS course or the article about the SQL JOIN interview questions. Hope you ace all the exercises that await you there! Tags: JOIN sql practice