Query posts based on previous query

As discussed in the comments, instead of using the ID query argument to get each 'calp_event'-type post individually, you can pass an array of IDs to post__in in order to grab them all at once, thus reducing the number of database transactions in your code to 2.

By creating an array mapping post IDs to event start dates from the results of your 3rd-party table query, you can easily obtain the value to pass to post__in by using array_keys() to get an array of just post IDs. Then later in the loop, you can look up the start date using the same post-ID-to-start-date map.

Since you’re looping through query results and using template tags in a manner similar to WordPress’s “Loop”, you might also consider using a new WP_Query object instead of get_posts() to allow you to use a more conventional “Loop” logic to display your results.

global $wpdb;

$today  = date('Y-m-d');
$events = $wpdb->get_results( "SELECT * FROM " . $wpdb->prefix . "calp_events WHERE start >= '$today' ORDER BY start ASC LIMIT 5" );

// Create an array using event post IDs as keys and start dates as values
$eventDates = array();
foreach( $events as $event ) {
  $eventDates[ $event->post_id ] = $event->start;
}

// Query for the 'calp_event' posts indicated by the earlier query.
// Since the keys of $eventDates are the post IDs returned by the previous query, 
// array_keys( $eventDates ) will return an array consisting of those IDs
$eventQuery = new WP_Query( array(
  'post_type' => 'calp_event',
  'post__in'  => array_keys( $eventDates )
) );

// Use conventional Loop logic to display your results
if( $eventQuery->have_posts() ) {
  while( $eventQuery->have_posts() ) {
    $eventQuery->the_post();

    // Accessing the $eventDates array with the current post ID as a key will produce
    // the event start date which that ID is mapped to.
    echo $eventDates[ get_the_ID() ] . ' ' . the_title() . '<br>';
  }

  // Reset global post data so we don't muck up the main query
  wp_reset_postdata();
}
else {
  echo 'No upcoming events!';
}

You could reduce this to a single query by using more advanced SQL to grab all of the necessary posts and event start-dates in one go.