如何创建两个视图的并集?


36

我试图得到用户节点和按“发布日期”排序的注释的并集。这篇文章链接到D6的沙盒项目,但7没有任何内容。

这篇文章有一个在D6中使用hook_views_pre_execute()和SQL UNION的示例。这不适用于具有视图3的D7。

我遇到了merlinofchaos的评论

因为我们现在正在使用Drupal的新查询生成器,所以该查询是一个SelectQuery对象,您将必须对其进行修改或替换。查找Drupal 7的新数据库层以获取更多信息。

有没有人举过一个例子,说明如何做到这一点,或者有其他解决方案结合两个视图吗?


这更多的是想法,而不是真正的答案:您应该能够基于用户创建一个视图,该视图将节点和注释都连接在一起(毕竟它们都只是实体:)。在我的第一次尝试中,我没有这样做,因为视图没有提供用户到评论之间的关系。但这应该很容易改变。(或者我只是忘记了什么)。
mojzis 2012年

我认为这与下面的答案相同:kt需要两个上下文过滤器(content.author =已登录用户或comment.author =已登录用户)。
uwe 2012年

我不这么认为:)我的意思是基于用户的观点,加入节点和评论。但是我感觉用户和评论之间的关系存在一些问题-我没有设法显示评论。
mojzis 2012年

我只是猜测,但是您不能使用searchapi来同时索引多个实体类型吗?一旦有了它,并且有一个供两个部分使用的字段,则可以使用它来构建这样的视图。
丹尼尔·韦纳

1
有一个沙箱项目“视图组织工会”为Drupal 7,请drupal.org/sandbox/jalama/1785294
Anoop约瑟夫

Answers:


15

这是一个经过测试的有效示例:

/**
 * Implements hook_views_pre_execute().
 */
function mymodule_views_pre_execute(view &$view) {
  if ($view->name == 'my_view') {
    $query1 = &$view->build_info['query'];

    // Basic setup of the second query.
    $query2 = db_select('another_table', 'at')
      ->condition('some_field', 0, '>')
      ->condition('some_other_field', 12345);

    // The number of fields (and their aliases) must match query1.
    // Get the details with:
    // dpm($query1->getFields());
    $query2->addField('at', 'some_field', 'alias1');
    $query2->addField('at', 'some_other_field', 'alias2');
    $query2->addField('at', 'some_other_field2', 'alias3');
    $query2->addField('at', 'some_other_field3', 'alias4');

    // Verify that queries are very similar.
    // dpq($query1);
    // dpq($query2);

    // Matrimony.
    $query1 = $query2->union($query1, 'UNION ALL');

    // Manual test.
    // dpm($query1->execute()->fetchAll());

  }
}

这适用于大多数视图。但是,某些样式插件可能会做一些花哨的东西,而这种技术无法使用(我正在为您查看的日历模块)。



2

我最终使用db_query()创建SQL UNION,然后使用theme()函数将其呈现为包括分页器的表布局。

对用户而言,它看起来像默认视图。另一个好处是我可以优化查询很多。我正在显示“我的朋友的活动”,如果您为此使用视图,它将创建您的朋友列表,并在SQL“ IN”子句中使用它,如果您有50条或100条以上的记录,这将非常慢。

我可以将朋友列表缩小为仅过去x天已登录该站点的朋友。

这是一个代码示例:

  // Two queries are required (friendships can be represented in 2 ways in the
  // same table). No point making two db calls though so a UNION it is.

  // Build up the first query.
  $query = db_select('flag_friend', 'f')
    ->condition('f.uid', $account->uid)
    ->condition('u.login', $timestamp, '>');
  $query->addExpression('f.friend_uid', 'uid');
  $query->innerJoin('users', 'u', 'u.uid = f.friend_uid');

  // Build up the second query.
  $query2 = db_select('flag_friend', 'f')
    ->condition('f.friend_uid', $account->uid)
    ->condition('u.login', $timestamp, '>');
  $query2->addExpression('f.uid', 'uid');
  $query2->innerJoin('users', 'u', 'u.uid = f.uid');

  // Return the results of the UNIONed queries.
  return $query->union($query2)->execute()->fetchCol();

1

为了将来参考,这是我将基于同一表的两个视图组合在一起的方法。基于具有相同字段数的不同表的视图也应应用相同的原则。

在以下情况下,由于格式设置为渲染实体,因此仅选择id。但是,如果要使用字段,则可以随时向具有较少字段的查询中添加其他虚拟字段,因为我在下面添加了时间戳。

/**
 * Implements hook_views_pre_execute().
 */
function MY_MODULE_views_pre_execute(&$view) {
  if ($view->name == 'VIEW_1' && $view->current_display == 'DISPLAY_OF_VIEW_1') {

    $view2 = views_get_view('VIEW_2');
    $view2->build('DISPLAY_OF_VIEW_2');

    $view->build_info['query']
    ->fields('table_alias', array('timestamp'))
    ->union(
        $view2->build_info['query']
        ->range()
        ->fields('table_alias', array('timestamp'))
        ->orderBy('timestamp', 'DESC')
    );

    $view->build_info['count_query']
    ->union(
        $view2->build_info['count_query']
        ->range()
    );
  };
}

0

我想象它遵循以下原则:

/** 
* Implements hook_views_pre_execute().
*/     
function mymodule_views_pre_execute(&$view) {
  if ($view->name == 'myview') {
    $query = $view->query;
    $other_view = views_get_view('otherview');
    $other_query = $other_view->query;
    $query = $query->union($other_query);
    $view->query = $query;
  }
}

尽管我还没有测试过。

一些链接可能会有所帮助:

http://api.drupal.org/api/drupal/includes!database!select.inc/function/SelectQueryInterface%3A%3Aunion/7

http://drupal.org/node/557318#comment-1991910


1
这似乎不能完全正常工作。$ view-> query是Views用来构建查询的中间对象。SelectQuery是$ view-> build_info ['query']。当您进行相应的编辑时,我无法摆脱“致命错误:调用未定义方法SelectQuery :: render_pager()”的错误。
mpdonadio

1
该数据库的测试代码有工会的例子api.drupal.org/api/drupal/...api.drupal.org/api/drupal/...
mikeytown2


这可能唯一可行的方法是,如果两个视图几乎完全相同。
大林

0

我遇到了一个称为“ 视图字段视图”的模块,该模块允许您将视图作为字段嵌入到另一个视图中。我本人还没有尝试过,但这可能对您有所帮助。


2
尽管“视图字段视图”确实可以同时获取注释和节点,但我不相信有一种方法可以仅对字段进行排序。
Letharion 2012年


0

一种不同的方法是创建节点和注释的提要(在URL中使用用户标识符的上下文过滤器),然后将这两个提要合并为一个新的提要,并按发布日期进行显示。


-2

全球二手车:PHP字段?您可以使用它们将胶带粘合在一起,从而将两者结合在一起。

使用“内容:标题”和“内容:注释”字段创建内容视图(从显示中排除)。

添加一个PHP字段,该字段计算哪个是最近的,用户最近一次更新的日期或用户最后一次评论的日期,并将该字段的值设置为该日期。将该字段添加为排序条件。

添加一个类似的字段,该字段将输出指向注释或节点的链接。

对我来说听起来不错!


有趣的主意。这将需要两个上下文过滤器(content.author =已登录用户或comment.author =已登录用户)。
uwe 2012年

希望在这一事件上获得史诗般的康复...;)
Johnathan Elmore

2
这种方法的性能下降将是可怕的。可能执行的数据库查询数量可能会超出天文数字。
Rider_X 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.