Example: Use a Pass-Through Query in a Subquery

The following example shows how to use a subquery that contains a pass-through query. A subquery is a nested query and is usually part of a WHERE or HAVING clause. Summary functions cannot appear in a WHERE clause, so using a subquery is often a good technique. A subquery is contained in parentheses and returns one or more values to the outer query for further processing.
This example creates an SQL view, Samples.AllEmp, based on Sybase data. Sybase objects, such as table names and columns, are case sensitive. Database identification statements and column names are converted to uppercase unless they are enclosed in quotation marks.
The outer PROC SQL query retrieves data from the SQL view; the subquery uses a pass-through query to retrieve data. This query returns the names of employees who earn less than the average salary for each department. The macro variable, Dept, substitutes the department name in the query.
libname mydblib sybase server=server1 database=personnel
   user=testuser password=testpass;
libname samples 'your-SAS-library';

/* Create SQL view */
proc sql;

   create view samples.allemp as
      select * from mydblib.employees;
   
quit;

/* Use the SQL pass-through facility to retrieve data */ 
proc sql stimer;

title "Employees Who Earn Below the &dept Average Salary";

connect to sybase(server=server1 database=personnel
   user=testuser password=testpass);
%put &sqlxmsg;

%let dept='ACC%';

select empid, lastname
   from samples.allemp
   where dept like &dept and salary <
         (select avg(salary) from connection to sybase
                (select SALARY from EMPLOYEES
                    where DEPT like &dept));
%put &sqlxmsg;
disconnect from sybase;
quit;
When a PROC SQL query contains subqueries or inline views, the innermost query is evaluated first. In this example, data is retrieved from the Employees table and returned to the subquery for further processing. The pass-through query is enclosed in parentheses (in italics), and another set of parentheses encloses the entire subquery.
When a comparison operator such as < or > is used in a WHERE clause, the subquery must return a single value. In this example, the AVG summary function returns the average salary of employees in the department, $57,840.86. This value is inserted in the query, as if the query were written:
where dept like &dept and salary < 57840.86;
Employees who earn less than the department's average salary are listed in the following output.
Output from a Pass-Through Query in a Subquery
   Employees Who Earn Below the 'ACC%' Average Salary

                    EMPID  LASTNAME  
                   ----------------
                   123456  VARGAS 
                   135673  HEMESLY 
                   423286  MIFUNE 
                   457232  LOVELL
It might appear to be more direct to omit the pass-through query and to instead access Samples.AllEmp a second time in the subquery, as if the query were written as follows:
%let dept='ACC%';

proc sql stimer;
select empid, lastname
   from samples.allemp
   where dept like &dept and salary <
         (select avg(salary) from samples.allemp
             where dept like &dept);
quit;
However, as the SAS log below indicates, the PROC SQL query with the pass-through subquery performs better. (The STIMER option in the PROC SQL statement provides statistics on the SAS process.)
SAS Log Comparing the Two PROC SQL Queries

213
214  %let dept='ACC%';
215
216  select empid, lastname, firstnam
217     from samples.allemp
218     where dept like &dept and salary <
219           (select avg(salary)
220               from connection to sybase
221                  (select SALARY from EMPLOYEES
222                      where DEPT like &dept));


NOTE: The SQL Statement used 0:00:00.2 real 0:00:00.20 cpu.
223  %put &sqlxmsg;

224  disconnect from sybase;
NOTE: The SQL Statement used 0:00:00.0 real 0:00:00.0 cpu.
225  quit;
NOTE: The PROCEDURE SQL used 0:00:00.0 real 0:00:00.0 cpu.

226
227  %let dept='ACC%';
228
229  proc sql stimer;
NOTE: The SQL Statement used 0:00:00.0 real 0:00:00.0 cpu.
230  select empid, lastname, firstnam
231     from samples.allemp
232     where dept like &dept and salary <
233           (select avg(salary)
234               from samples.allemp
235               where dept like &dept);


NOTE: The SQL Statement used 0:00:06.0 real 0:00:00.20 cpu.