主题:【求助】实现送花功能的SQL语法求助,回复者花 -- 卷心菜
最近想给某个论坛实现类似河里送花的功能,遇上一个难题。
先简单地说一下论坛资料库结构:
ipf_posts---记录所有post的表格(所有主题帖与回复帖的具体发言、状态,包括所属的主题id,发言时间,发言者名称和id等等)。
ibf_topics---记录所有topic的表格(主题id、名称、发表时间、主题发起者的名称和id等等,但不包含任何具体发言内容)。
下面这段code是在特定论坛版面显示该版主题列表的mysql query:
LEFT JOIN ibf_posts ON
(ibf_topics.tid=ibf_posts.topic_id AND ibf_posts.author_id=".$ibforums->member['id'].")
WHERE ibf_topics.forum_id=".$this->forum['id']."
这段源码的效果是从ibf_topics中找出应该在本版显示的topic。其本质就是SELECT ibf_topics.* WHERE ibf_topics.forum_id=".$this->forum['id']。那些SELECT DISTINCT和LEFT JOIN ibf_posts只是为了把使用者参予过的主题在主题列表中标示出来。
现在在(ibf_posts)中有rep_inc(花)和rep_dec(草)这两栏,记录每帖收花、收草的数量。我打算在显示主题列表时把主题帖(该主题第一个发言)的收花/草数也显示在主题列表上,如同西西河一样。可是怎样在显示主题列表的query当中把记录在ibf_posts的花草数量也一并查出来呢?
ibf_topics中有主题发起者的id和发表时间,ibf_posts中同样有发表者id和发表时间,通过比较两者就可以从ibf_posts找到相应的row并挖出该主题帖的rep_inc(花)和rep_dec(草)。问题是query要怎样写?
如果分开来做,比如说先执行topic query然后根据每行的结果再去执行ibf_posts的query找出花草数量,理论上会比较简单。但是根据该论坛的排版,一个主题列表会有好几十行结果,变相每次显示主题列表要额外执行好几十次query,效率恐怕会大打折扣,所以我不打算使用这一方法。
我不常接触SQL,想了好久还是想不出什么,请大家帮帮忙吧。
===============================
更直观地说:
ibf_topics
ibf_posts
其实我想做的就是在
SELECT * from ibf_topics WHERE forum_id=".$this->forum['id']."
之余把两个表中的id和date(橙色部份)比较一下,把ibf_posts里面match的那个row当中的rep_inc和rep_dec栏合并到ibf_topics被SELECT的row上面。
为什么不把 花rep_inc 草rep_dec 的纪录直接放在主题表 ibf_topics?
主题表只是每个主题有一行记录,但一个主题可以有多个帖子,每个帖子有各自的花草数量,所以只能放在帖子表ibf_posts。
LEFT JOIN ibf_posts ON
(ibf_topics.tid=ibf_posts.topic_id AND ibf_posts.author_id=".$ibforums->member['id'].")
WHERE ibf_topics.forum_id=".$this->forum['id']."
这可能是你想要的结果,做个多表查询
select ibf_topics.*,ipf_posts.rep_inc,ipf_posts.rep_dec
from
ibf_topics,ipf_posts
where
ibf_topics.forum_id=ipf_posts.forum_id
或者
select ibf_topics.forum_id,sum(ipf_posts.rep_inc),sum(ipf_posts.rep_dec)
from
ibf_topics,ipf_posts
where
ibf_topics.forum_id=ipf_posts.forum_id
group by ibf_topics.forum_id
这样会导致部份主题在主题列表上重复出现,我猜这是由于LEFT JOIN时同一个ibf_topics.tid会对应多于一个的ibf_posts的row,而且光是这样的话没办法知道选出来的哪个才是主题帖。
原本的code只选ibf_posts.author_id没有造成重复问题是因为用了SELECT DISTINCT(ibf_posts.author_id),再加上后面的LEFT JOIN ... ON
(ibf_topics.tid=ibf_posts.topic_id AND ibf_posts.author_id=".$ibforums->member['id'].")条件使得ibf_posts对应ibf_topics时必然是一行对一行,可是加上ibf_posts.rep_inc和rep_dec之后就不止一行了,因为同一个主题内可能有多个发言收到了花/草。
我修改了一下主帖的描述,上了两幅截图,可能会清晰一些?
ibf_topics
ibf_posts
其实我想做的就是在
SELECT * from ibf_topics WHERE forum_id=".$this->forum['id']."
之余把两个表中的id和date(橙色部份)比较一下,把ibf_posts里面match的那个row当中的rep_inc和rep_dec栏合并到ibf_topics被SELECT的row上面。
也许没有必要区分主题贴和跟帖,一个表记录所有帖子,内容倒是可以放到子表当中
就不画图了,写下来,应该不难懂
有三张表
建立post表,记录帖子标题、相关信息,有parent_id和记录id字段建立关联,可以很方便建树,
建立post_content表,记录帖子内容,有字段 post_id作为外键和post表建立关系,
建立comment表,记录送的花花草草和相关信息,有post_id作为外键和post表建立关系
这样在平面显示帖子列表,象西西河这样每个帖子显示局部讨论串,以及书展都很方便
羽羊胡言乱语,各位大牛拍砖
和您想法差不多。
建立post表,记录除帖子内容外的所有主帖属性,在LIST的时候比较方便
建立post_content表,记录帖子内容,有字段 post_id作为外键和post表建立关系,
建立comment表,记录回帖内容及回帖属性,有post_id作为外键和post表建立关系
PS:其实这还和你想将主帖与跟帖如何定位有关。如果跟帖只是从属于主帖,不会有让跟帖单独展示的需求,那跟帖单独建表是OK的。如果跟帖的地位比较高,可以与主帖等同(像河里),那可以考虑跟帖主帖用同一张表。
河友轻点拍砖~
在ibf_posts表中加一个字段作为标志位,比如primary_post,标明是否是首发贴,处理起来会简单得多,这时SQL可以这样写:
$query = "SELECT DISTINCT(ibf_posts.author_id), ibf_topics.* FROM ibf_topics
LEFT JOIN ibf_posts ON
(ibf_topics.tid=ibf_posts.topic_id AND ibf_posts.primary_post = true)
WHERE ibf_topics.forum_id=".$this->forum['id']."
只要选取顶楼的就行了
其实讨论版核心用的是现成的程序,需要什么功能里面没有自己再改,这样省心很多。
当然,基本的资料库架构我就保留原样了,主题帖和跟帖并没有分开(内容都在ibf_posts表里边),只是关于主题标题等资讯另有一个表,前者类似于你说的post_content表,后者类似于你说的post表。花花草草我整合在发帖表里面,反正也只是两栏。
除了这些,还有很多其他大大小小的表(会员资料、短信、讨论版、分类、等级设定、管理记录......)好几十个。
要是全部自己写,不知要写到什么时候,呵呵。
不过我还是用比较发帖时间与id的方式达到了同样效果。
如果重头开始设计的话你的建议更好,只是我那个讨论版已经在运作,有十来万留言,再改表结构有些麻烦。
论坛程序算是web程序当中复杂程度很高的了,现在开源的东西也多,没必要自己动手发明轮子了,说到这儿尤其佩服铁手了。给他的回复献朵花去。。。
最后写成这样了,透过比较发帖id和时间辨认哪个是首发帖,放弃原本‘标示使用者参予帖’的功能,不然没法拿LEFT JOIN一物两用。
LEFT JOIN ibf_posts ON
(ibf_topics.starter_id=ibf_posts.author_id AND ibf_topics.start_date=ibf_posts.post_date)
WHERE ibf_topics.forum_id=".$this->forum['id']."