web-dev-qa-db-ja.com

ビュー3とサブクエリ?

複数の結合を行うクエリを生成するビューを持っています。これはデカルト結合を生成し、結合をサブクエリに「変換」する必要があります。

ドキュメント、Google検索結果、その他のソースを調べましたが、サブクエリを実行するようにビューを構成する方法についての適切な説明が見つかりません。 hook_views_data()を使用して関係を構成しました(現在は結合として実行されています)。どういうわけか、hook_views_data()を介してサブクエリを定義することは可能ですか、それとも別のアプローチをとる必要がありますか?

どんな助言も感謝します!

12
sbrattla

さらに調べましたが、これを説明するドキュメントは実際には見つかりませんでした。

私が必要としたのは、usersテーブルを、ユーザーのデータを保持する他の2つのテーブルと結合する方法です。ただし、他の2つのテーブルは、usersテーブルと「1対多」の関係にあります。つまり、usersテーブルをこれらのテーブルの両方に同時に結合しようとすると、デカルト結合になります。 。ただし、必要なのは、特定のユーザーに関連付けられている他の2つのテーブルのレコード数を数えることだけなので、サブクエリでうまくいくはずです。ただし、ビューとサブクエリに関するドキュメントは見つかりませんでした。ここに私がやったことを示します。

  1. 2つのダミーフィールドを作成しました

Hook_views_data()を介して2つのダミーフィールド(「downloads」と「listens」と呼びます)を作成しました。フィールドの定義を以下に示します。

function hook_views_data() {

  $data['users'] = array(
    'downloads' => array(
      'title' => t('Downloads'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    ),
    'listens' => array(
      'title' => t('Listens'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    )
  ),
);

これで、ユーザーのビューを構成すると、「ダウンロード」および「リッスン」フィールドが表示されます。ただし、クエリを実行しようとすると、ダミーフィールドがすべてダミーフィールドになるため、エラーが発生します。それらは存在しません。これらのフィールドの唯一の目的は、いくつかのreplacemenetsを実行する必要があることをhook_views_query_alter()の実装に通知することです。

  1. Hook_views_query_alter()を実装する

ここでの秘訣は、指定されたクエリに「ダウンロード」または「リッスン」フィールドが含まれているかどうかを確認することです。含まれている場合は、クエリからフィールドを削除して、サブクエリに置き換えます。この関数の実装は以下のようになります。

function mta_views_query_alter(&$view, &$query) {

  foreach ($query->fields as $field_key => &$field_values) {
    if ($field_values['table'] == 'users') {

      switch ($field_values['field']) {
        case 'downloads':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 0)", $field_key);
          break;
        case 'listens':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 1)", $field_key);
          break;
      }
    }
  }
}

削除されたフィールドのエイリアスをサブクエリに再利用していることに注意してください。そうすることで、ビューはサブクエリから返された値が実際にはダミーフィールド(結局存在しない)からのものであると見なします。

それです。デカルト結合が得られず、「ダウンロード」と「リッスン」の両方が正しくカウントされます。

5
sbrattla

サブクエリにフィルター値を継承させる必要があるまで、sbrattlaのソリューションを使用しました。 views_field_view モジュールを使用して、カウントクエリを実行する別のビューを埋め込みます。 views_filterfield モジュール(私が書いた)を介して、コンテキストフィルターの値を埋め込みビューに渡すことができます。

カウントクエリが機能し、メインクエリで公開されているフィルターを継承します。

4
Cafuego