MySQL获取行,但对于任何匹配获取最新版本

时间:2010-07-05 14:56:58

标签: activerecord codeigniter mysql

我正在开发CMS,并通过使用当前时间戳向数据库添加新条目来实现版本控制。

我的表格设置如下:

id | page | section | timestamp | content

“页面”是被访问的页面,它是页面的路径(下面的$ page_name)或'/'(表示'全局'字段)。

“部分”是正在编辑的页面的部分。

我希望能够为给定页面选择所有行,但每个部分只应选择一次,选择最新时间戳的那一行。

我尝试使用以下CodeIgniter Active Record代码:

$this->db->select('DISTINCT(section), content');
$this->db->where_in('page', array('/', $page_name));
$this->db->order_by('timestamp', 'desc');
$query = $this->db->get('cms_content');

生成以下SQL:

SELECT DISTINCT(section), `content`
FROM (`cms_content`)
WHERE `page` IN ('/', 'index.html') 
AND `enabled` = 1
ORDER BY `timestamp` desc

返回两个测试行(除了id,timestamp和content之外,所有行都有相同的字段)。

关于我哪里出错的任何想法?

谢谢!

3 个答案:

答案 0 :(得分:2)

你的错误是认为DISTINCT仅适用于部分 - 这是一个容易犯的错误,因为括号在这里会产生误导。事实上,无论你是否有括号,DISTINCT都适用于整行。因此,最好省略括号以避免混淆。

您的问题是典型的“每组最大”问题。编写此查询有很多种方法,它可能是此网站上最受欢迎的SQL问题之一,因此您可以search Stack Overflow找到解决方法。开始使用的一种方法是仅选择包含该部分的最大时间戳的行:

SELECT section, content
FROM cms_content T1
WHERE page IN ('/', 'index.html') 
AND enabled = 1
AND timestamp = (
    SELECT MAX(timestamp)
    FROM cms_content T2
    WHERE page IN ('/', 'index.html') 
    AND enabled = 1
    AND T1.section = T2.section
)

我很抱歉,但我不知道如何将此SQL代码转换为CodeIgniter Active Record。如果另一个更熟悉Active Record的用户希望将此作为自己答案的起点,欢迎使用。

答案 1 :(得分:1)

DISTINCT适用于所有选定的列,因为“内容”不同,您将获得两个不同的行。

您只想按时间戳排序并限制1,因为您总是想要最新的。

但我可以建议您对“活动”页面进行交叉引用吗?这样,您就可以在不转储新版本的情况下恢复到以前的版本。

含义:

page
----
id
info
active_page_id


page_revisions
--------------
id
page_id
content
timestamp
...

意思是,页面< - >之间有一对多page_revisions,以及页面和page_revisions之间的一对一,以跟踪“当前”修订。使用这种方法,您只需加入活动版本。

答案 2 :(得分:0)

这将在Codeigniter中完成,没有临时表:

$this->db->query( "SELECT *
    FROM cms_content AS c1
    LEFT JOIN cms_content AS c2 
        ON c1.page=c2.page 
        AND c1.section=c2.section 
        AND c1.timestamp < c2.timestamp
    WHERE c2.timestamp IS NULL AND page=?", $page );