我正在开发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之外,所有行都有相同的字段)。
关于我哪里出错的任何想法?
谢谢!
答案 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 );