Is it possible to join dynamic tables (subqueries) using db_select()? I've got a complex query I'm trying to convert to db_select().

SELECT c.cid, c.pid, c.thread, count.replies, SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1)) as torder 
FROM comment c 
JOIN(
    SELECT count(*) as replies, SUBSTRING_INDEX(LEFT(thread, LENGTH(thread) -1 ), '.', 1) as torder 
    FROM comment 
    WHERE nid = 1 
    GROUP BY torder
) as count 
ON SUBSTRING_INDEX(LEFT(c.thread, LENGTH(c.thread) -1 ), '.', 1) = count.torder 
WHERE c.nid = 1 ORDER BY count.replies DESC, torder ASC;


I'm not sure how join through a select statement, if it is possible, or if there is another alternative.

I don't need to return anything from the join (count.replies is only there for show) so maybe there is another option other than join.

I'm trying to select order by the top-level comment with the highest number of replies and it's children. 

The result prints this for my test data:

+-----+-----+-----------------+---------+----------------+
| cid | pid | thread          | replies | torder         |
+-----+-----+-----------------+---------+----------------+
| 262 |   0 | 03/             |      11 | 03             |
| 269 | 262 | 03.00/          |      11 | 03.00          |
| 272 | 269 | 03.00.00/       |      11 | 03.00.00       |
| 270 | 262 | 03.01/          |      11 | 03.01          |
| 273 | 270 | 03.01.00/       |      11 | 03.01.00       |
| 275 | 273 | 03.01.00.00/    |      11 | 03.01.00.00    |
| 276 | 275 | 03.01.00.00.00/ |      11 | 03.01.00.00.00 |
| 280 | 275 | 03.01.00.00.01/ |      11 | 03.01.00.00.01 |
| 277 | 270 | 03.01.01/       |      11 | 03.01.01       |
| 278 | 270 | 03.01.02/       |      11 | 03.01.02       |
| 271 | 262 | 03.02/          |      11 | 03.02          |
| 264 |   0 | 04/             |       3 | 04             |
| 281 | 264 | 04.00/          |       3 | 04.00          |
| 282 | 264 | 04.01/          |       3 | 04.01          |
| 260 |   0 | 01/             |       2 | 01             |
| 279 | 260 | 01.00/          |       2 | 01.00          |
| 261 |   0 | 02/             |       2 | 02             |
| 274 | 261 | 02.00/          |       2 | 02.00          |
| 283 |   0 | 05/             |       1 | 05             |
+-----+-----+-----------------+---------+----------------+


The 'replies' number includes the top level comment which is OK because I'm only using this for ordering and includes all of the comments in a thread for each comment which is by design because I want to group all of the comments first by how many comments are in their group.

The SELECT in the join returns the number of replies for each top level comment:

+---------+----------+
| replies | torder   |
+---------+----------+
|       2 | 01       |
|       2 | 02       |
|      11 | 03       |
|       3 | 04       |
|       1 | 05       |
+---------+----------+


I can't to this using db_query because I'm trying to overwrite the query in comment_get_thread() using hook_query_TAG_alter().

I've tried using $query-&gt;join() but don't see where it is possible to put in an argument. 

EDIT:

Thanks so much for your answers. Here is the db_select translation of the sql query above if anyone is having trouble with this in the future:

$subquery = db_select('comment', 'c')
  -&gt;fields('c', array('thread'))
  -&gt;condition('c.nid', '1134');
$subquery-&gt;addExpression('COUNT(*)', 'replies');
$subquery-&gt;addExpression('SUBSTRING_INDEX(LEFT(c.thread, LENGTH(c.thread) -1 ), \'.\', 1)', 'toporder');
$subquery-&gt;groupBy('toporder');
$query = db_select('comment', 'c')
  -&gt;fields('c', array('cid', 'pid'))
  -&gt;condition('c.nid', '1134');
$query-&gt;addExpression('SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))', 'torder');
$query-&gt;addJoin('', $subquery, 'count', 'SUBSTRING_INDEX(LEFT(c.thread, LENGTH(c.thread) -1 ), \'.\', 1) = count.toporder ');
$query-&gt;orderBy('count.replies', 'DESC');
$query-&gt;orderBy('torder', 'ASC');
$results = $query-&gt;execute()-&gt;fetchAll();
Both db_select and addJoin documentation says clearly that the table


  May be a string or another SelectQuery object. If a query object is passed, it will be used as a subselect.


So, 

$sub_select = db_select('comment');
// Convert.
$select = db_select('comment')-&gt;addJoin($sub_select...