それは遊び場です:
CREATE TABLE `feed`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`tm` INT UNSIGNED NOT NULL COMMENT 'timestamp',
`user_id` INT UNSIGNED NOT NULL COMMENT 'author id',
`image` VARCHAR(255) NOT NULL COMMENT 'posted image filename',
`group` INT UNSIGNED NULL DEFAULT NULL COMMENT 'post group',
PRIMARY KEY(`id`),
INDEX(`user_id`),
INDEX(`tm`,`group`)
);
時間的に近い投稿をまとめたいと思います。
まず、必要な粒度を宣言します: 時間的近接性に対するしきい値:
SET @granularity:=60*60;
各行は、行 ID と一致するグループ ID (タイムスタンプの場合もあります) を持つグループを形成します。
SELECT `g`.`id` AS `group`
FROM `feed` `g`;
各グループには、グループ形成者よりも前に投稿された、同じユーザーから発信された行が含まれています。
SELECT `g`.`id` AS `group`, `f`.*
FROM `feed` `g`
CROSS JOIN `feed` `f`
ON (`f`.`user_id` = `g`.`user_id`
AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
)
各行は複数のグループに属しています。行ごとに、最も「広い」グループを選択します。つまり、rowId が最大です。
SELECT MAX(`g`.`id`) AS `group`, `f`.*
FROM `feed` `g`
CROSS JOIN `feed` `f`
ON (`f`.`user_id` = `g`.`user_id`
AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
)
GROUP BY `f`.`id`
最近更新されたグループが常に先頭にジャンプします ( group
DESC で並べ替えた場合)。ただし、グループを永続的にしたい場合 (たとえば、アイテムがあるグループから別のグループに移動しないようにする場合) は、MIN
代わりにMAX
次を使用します。
SELECT MIN(`g`.`id`) AS `group`, `f`.*
FROM `feed` `g`
CROSS JOIN `feed` `f`
ON (`f`.`user_id` = `g`.`user_id`
AND `f`.`tm` BETWEEN `g`.`tm` AND `g`.`tm`+@granularity
)
GROUP BY `f`.`id`
次に、テーブルのgroup
列を更新します。まず、MySQL は読み取り元と同じテーブルを更新できません。一時テーブルが必要です。group
2 番目:列が NULL の行、または より後に投稿された行のみを更新しますUNIX_TIMESTAMP()-2*@threshold
。
CREATE TEMPORARY TABLE `_feedg`
SELECT MAX(`g`.`id`) AS `group`, `f`.`id`
FROM `feed` `g`
CROSS JOIN `feed` `f`
ON (`f`.`user_id` = `g`.`user_id`
AND `f`.`tm` BETWEEN `g`.`tm`-@granularity AND `g`.`tm`
)
WHERE `f`.`group` IS NULL
OR `f`.`tm` >= (UNIX_TIMESTAMP()-2*@granularity)
GROUP BY `f`.`id`;
列を更新しgroup
ます。
UPDATE `feed` `f` CROSS JOIN `_feedg` `g` USING(`id`)
SET `f`.`group` = `g`.`group`;
SQLFiddle は次のとおりです。http://sqlfiddle.com/#!2/be9ce/15