Thanks for the suggestion. I actually already did that, and the results are really strange. Here's what's taking place:
From datawindow:
(1) Stored procedure creates a temp table and populates it with 62050 rows (unique account records);
(2) Stored procedure calculates a total paid for each account (row) based on transactions in a linked table;
(3) Stored procedure deletes all records from temp table with a total paid amount < $100,000 (exactly 281 remain when I use a particular set of date values and account types);
From Query Analyzer (copy and paste, verbatim, the statement from Profiler):
(1) Stored procedure creates a temp table and populates it with 64,786 rows (exactly 2,736 more);
(2) Stored procedure calculates a total paid for each account based on transactions in a linked table;
(3) Stored procedure deletes all records from temp table with a total paid amount < $100,000 (exactly 300 remain).
If I reduce the number of initial records (e.g., 30,000) by changing some of my selection argument values, the rows returned by the datawindow are consistent with the rows returned by Query Analyzer. Specifically, the original selection represented account dates 1/1/1979 - 9/30/2006 (the date the account was opened). If I break it up into two groups, (1/1/1979 - 12/31/1992 and 1/1/1993 - 9/30/2006), the collective number of rows returned by the datawindow is 300.
The only possible explanation I can come up with is that there must be something afoul with the OLEDB connection, but what, exactly, I have no idea. I would think that the statement would be passed to the server, then the server would do exactly the same work that it would do if the statement came from any other source, and the small number of rows would be returned correctly. This has to be one of the strangest "quirks" I've ever seen with PowerBuilder (or SQL Server, whichever is responsible), and I have no idea how to fix it.