chapter 14 Subqueries Keyword Introduced: EXISTS In Chapter 4, we talked about composite functions. These were functions that contained other functions. In a similar manner, it is possible for SQL queries to contain other queries. The queries that are contained within other queries are called subqueries. The topic of subqueries is somewhat complex, primarily because there are many different ways in which they can be used. Subqueries can be found in many dif- ferent parts of the SELECT statement, each with different nuances and require- ments. As a query contained within another query, subqueries can be related to and dependent on the main query, or they can be completely independent of the main query. Again, this distinction results in different usage requirements. No matter how subqueries are used, they add a great deal of flexibility to the ways in which you can write SQL queries. It many cases, subqueries provide func- tionality that could be accomplished by other means. In such instances, personal preferences will come into play as you decide whether or not you want to utilize the subquery solution. However, as you will see, there are certain situations where subqueries are absolutely essential for the task at hand. With that, let’s begin our discussion with an outli ne of the basic types o f subqueries. Types of Subqueries Subqueries can be utilized not only with SELECT statements, but also with the INSERT, UPDATE, and DELETE statements, which will be covered in 141 Chapter 17. In this chapter, however, we’re going to restrict our discussion of subqueries to the SELECT. Here’s the general SELECT statement that we have seen: SELECT columnlist FROM tablelist WHERE condition GROUP BY columnlist HAVING condition ORDER BY columnlist Subqueries can be inserted into virtually any of the clauses in the SELECT statement. However, the way in which the subquery is stated and used varies slightly, depending on whether it is used in a columnlist,atablelist,ora condition. But what exactly is a subquery? A subquery is merely a SELECT statement that is inserted inside another SELECT statement. Additionally, a SELECT statement can have more than one subquery. To sum up, there are three main ways in whic h subqueries can be specified: ■ When a subquery is part of a tablelist, it specifies a data source. ■ When a subquery is part of a condition, it becomes part of the selection criteria. ■ When a subquery is part of a columnlist, it creates a single calculated column. The remainder of this chapter will explain each of these three scenarios in detail. Using a Subquery as a Data Source When a subquery is specified as part of the FROM clause, it instantly creates a new data source. This is similar to the concept of creating a view and then referencing that view in a SELECT. The only difference is that a view is permanently saved in a database. A subquery used as a data source isn’t saved. It exists only tempora- rily, as part of the SELECT statement. Chapter 14 ■ Subqueries142 We will first consider an example that illustrates how subqueries can be used as data sources. Let’s say we have this Customers table: CustomerID CustomerName 1 William Smith 2 Natalie Lopez 3 Brenda Harper 4 Adam Petrie Also, this Orders table: OrderID CustomerID OrderAmount OrderType 1 1 22.25 Cash 2 2 11.75 Credit 3 2 5.00 Credit 4 2 8.00 Cash 5 3 9.33 Credit 6 3 10.11 Credit We would like to see a list of customers, along with a total sum of the cash orders they have placed. The following SELECT accomplishes that task: SELECT CustomerName AS 'Customer Name', ISNULL (CashOrders.SumOfOrders, 0) AS 'Total Cash Orders' FROM Customers LEFT JOIN (SELECT CustomerID, SUM (OrderAmount) as 'SumOfOrders' FROM Orders WHERE OrderType ¼ 'Cash' GROUP BY CustomerID) AS CashOrders ON Customers.CustomerID ¼ CashOrders.CustomerID ORDER BY Customers.CustomerID Two blank lines were inserted to clearly separate the subquery from the rest of the statement. The subquery is the middle section of the statement. Using a Subquery as a Data Source 143 The results were: Customer Name Total Cash Orders William Smith 22.25 Natalie Lopez 8.00 Brenda Harper 0 Adam Petrie 0 Adam Petrie shows no cash orders, since he didn’t place any orders. Even though Brenda Harper placed two orders, they were both credit orders, so she also shows no cash orders. Note that the ISNULL function converts the NULL values that would normally appear for Adam and Brenda to a 0. Let’s now analyze how the subquery works. The subquery in the previous state- ment is: SELECT CustomerID, SUM (OrderAmount) as 'Total Cash Orders' FROM Orders WHERE OrderType ¼ 'Cash' GROUP BY CustomerID In general form, the main SELECT statement in the above is: SELECT CustomerName AS 'Customer Name', ISNULL (OrderCounts.SumOfOrders, 0) AS 'Total Cash Orders' FROM Customers INNER JOIN (subquery) AS CashOrders ON Customers.CustomerID ¼ CashOrders.CustomerID ORDER BY Customers.CustomerID If the subquery were executed by itself, the results would be: CustomerID SumOfOrders 1 2.25 28 Chapter 14 ■ Subqueries144 We only see data for customers 1 and 2. The WHERE clause in the subquery enforces the restriction that we only look at cash orders. In this example, the entire subquery is referenced as if it were a separate table or view. Notice that the subquery is given a table alias of CashOrders, which allows the columns in the subquery to be referenced in the main SELECT. As such, the following line in the main SELECT references data in the subquery: ISNULL (CashOrders.SumOfOrders, 0) AS 'Total Cash Orders' CashOrders.SumOfOrders is a column that is taken from the subquery. Is it truly necessary to use a subquery to obtain the desired data? In this case, the answer is yes. We might have attempted to simply join the Customers and Orders tables via a left join, as in the following: SELECT CustomerName AS 'Customer Name', Sum (OrderAmount) AS 'Total Cash Orders' FROM Customers LEFT JOIN Orders ON Customers.CustomerID ¼ Orders.CustomerID WHERE OrderType ¼ 'Cash' GROUP BY Customers.CustomerID, CustomerName ORDER BY Customers.CustomerID However, this statement yields the following data: Customer Name Total Cash Orders William Smith 22.25 Natalie Lopez 8.00 We no longer see any rows for Brenda Harper or Adam P etrie, beca use the WHERE clause exclusion for cash order s is now i n the mai n quer y rather than in a subquery. As a result, w e n o l onger see any rows for cust omers who didn’t place cash orders. Using a Subquery in Selection Criteria In Chapter 8, we introduced the first format of the IN operator. The example we used was: WHERE State IN ('IL', 'NY') Using a Subquery in Selection Criteria 145 . inserted to clearly separate the subquery from the rest of the statement. The subquery is the middle section of the statement. Using a Subquery as a Data Source 143 The results were: Customer Name. which allows the columns in the subquery to be referenced in the main SELECT. As such, the following line in the main SELECT references data in the subquery: ISNULL (CashOrders.SumOfOrders, 0). calculated column. The remainder of this chapter will explain each of these three scenarios in detail. Using a Subquery as a Data Source When a subquery is specified as part of the FROM clause,