How do I select entries that have a particular block type? Say I have a channel with a matrix field which has two block types - text and video. Is there any way to select all entries in that channel that have a video block?

Idea 1

Use the Low Blocks plugin to query all video block types, then get their owner IDs, then use those to grab the entries.

Idea 2

Add a light switch field to the channel called "hasVideo". Update this field programmatically using the onSave event and a plugin. Then I can select all entries if hasVideo is true.

Is there a better way I'm missing?
You can write a custom plugin and make use of Craft's buildElementsQuery, to be able to add custom query statements to your ElementCriteriaModel.

Give your plugin a Template Variable addVideoBlockCriteria and with some lines of plugin code you will be able to do something like this from your template:

{% set criteria = craft.entries.section('blog').order('title asc') %}
{% set entries = craft.businesslogic.addVideoBlockCriteria(criteria) %}

{% for entry in entries %}
    ...
{% endfor %}


Make your Template Variable pass the criteria to a plugin service, run them through buildElementsQuery, and you can now modify the query with some DbCommands.

public function addVideoBlockCriteria(ElementCriteriaModel $criteria)
{
    $query = craft()-&gt;elements-&gt;buildElementsQuery($criteria);

    $query-&gt;andWhere('matrixcontent_article.field_video_videoUrl is not null');

    $query-&gt;join('matrixblocks matrixblocks', 'matrixblocks.ownerId = entries.id');
    $query-&gt;join('matrixcontent_article matrixcontent_article', 'matrixcontent_article.elementId = matrixblocks.id');

    $results = $query-&gt;queryAll();

    return EntryModel::populateModels($results);
}


Use join to bring in the "matrixblocks" table and also your Matrix field's content table "matrixcontent_mymatrixfield". And add the conditions with andWhere;  the Matrix field's fields column names follow a scheme "field_myMatrixBlockType_myFieldInMatrixBlock".