Yii -按日期为每个类型字段选择前5条记录


yii - select first five records for each type field ordered by date

我有一个包含以下字段的表:

Advertisements (
  id bigint 20,
  name varchar 255,
  content text,
  creator_id bigint 20,
  type_id bigint 255 DEFAULT VALUE IS NULL,
  create_date bigint 20
)

我需要选择按日期排序的每种类型的前5条记录(我需要最新的)。我还想用CActiveDataProvider的结果。除了sql查询器之外,是否有任何方法可以使用模型函数或yii集成函数获得记录(原因:我还需要在广告类中提供关系)?

其他表:

Users (
  id bigint 20,
  login varchar 255,
  password varchar 255,
  email varchar 255,
  date_of_registration bigint 20,
  status varchar 255
)
(The table with types)
Items (
  id bigint 20,
  item varchar 255,
  link varchar 255
)
Comments (
  id bigint 20,
  creator_id bigint 20,
  ......
  topic_id bigint 20
)
Rating (
  id bigint 20,
  creator_id bigint 20,
  ......
  topic_id bigint 20
)

我想拥有create_date订购的广告中每个type_id的最新记录,如果一个类型的记录数量超过5,则只选择最近的5条。另外,我想有登录的创建者+评论数+评级表完全?我知道这是可以通过SQL解决的,但我不知道如何做到这一点,因为我不擅长SQL。任何帮助都是感激的。谢谢大家的帮助。

根据James K. Lowden的提示在谷歌上搜索了一组后,我找到了下一个答案:

SELECT t.id,
        t.name,
        t.content,
        i.item,
        c.context
FROM (SELECT tbl.id,
            tbl.name,
            tbl.content,
            tbl.owner_id,
            tbl type_id,
            CASE 
                WHEN tbl.type_id = @category THEN @rownum := @rownum + 1
                ELSE @rownum := 1
            END AS num,
            @category := tbl.type_id
        FROM Advertisements tbl
        JOIN (SELECT @rownum := 0, @category := NULL) r
        ORDER BY tbl.type_id, tbl.create_date DESC) t
LEFT JOIN Items i ON t.type_id = i.id
LEFT OUTER JOIN Comments c ON c.topic_id = t.id
WHERE t.num <= 5

如果我理解你的权利,这样的东西应该工作(未测试)。你应该在(type_id, date)上有一个索引

// Extract unique types. Perhaps you have table `type` and should do this other way but since you provided info only on Advertisements table I'm using what I got
$types = YII::app()->db->createCommand("SELECT DISTINCT type_id FROM Advertisements;")->queryColumn();
$resultsAll = array();
foreach ($types as $type_id) {
    $results = Advertisments::model()->findAll(
            array("condition" => "type_id = $type_id", "order" => "date DESC", "limit" => 5)
    );
    $resultsAll = array_merge($resultsAll, $results);
}
$dataProvider = new CArrayDataProvider($resultsAll, array());

我不确定我理解你所说的每个类型 是什么意思,或者为什么你不想用SQL来做SQL设计的目的。

如果使用规范查询对类型进行排序,

select a.id, a.name, a.content, 
       a.creator_id, a.type_id, count(b.id) as Rank
from Advertisements as a join Advertisements as b
on    a.id = b.id
and   a.name = b.name
and   a.content = b.content
and   a.creator_id = b.creator_id
and   a.type_id >= b.type_id
group by a.id, a.name, a.content, a.creator_id, a.type_id
having count(b.id) <= 5

and advertising由GROUP by子句中的列索引,查询运行时间为O(n log n)。在大多数情况下,它与O(n)难以区分,这很难被打败。

如果您关心性能,您可能需要重新考虑列的大小。我不知道bigint 20是什么,但是MySQL的bigint是64位。你真的期望超过40亿个创作者或类型吗?你确定名字必须超过30个字符吗?如果您现在做出的选择限制太大,那么以后可以更改所有这些选择,但是太大的选择将从第一天开始降低性能。

使用CDBCriteria。例子:

function actionIndex()
{
    ...
    $_criteria = new CDbCriteria();
    $_criteria->order = 'create_date DESC';
    $_criteria->limit = 5;
    $_ads = new CActiveDataProvider('Advertisements', array('criteria' => $_criteria));
    ...
    $this->render('index', array(
        ...
        'ads' => $_ads,
        ...
    );
}