西西河

主题:【求助】实现送花功能的SQL语法求助,回复者花 -- 卷心菜

共:💬23 🌺28 新:
全看树展主题 · 分页 下页
家园 【求助】实现送花功能的SQL语法求助,回复者花

最近想给某个论坛实现类似河里送花的功能,遇上一个难题。

先简单地说一下论坛资料库结构:

ipf_posts---记录所有post的表格(所有主题帖与回复帖的具体发言、状态,包括所属的主题id,发言时间,发言者名称和id等等)。

ibf_topics---记录所有topic的表格(主题id、名称、发表时间、主题发起者的名称和id等等,但不包含任何具体发言内容)。

下面这段code是在特定论坛版面显示该版主题列表的mysql query:

$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.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上面。

关键词(Tags): #SQL
家园 为什么不把 花草的纪录直接放在主题表?

为什么不把 花rep_inc 草rep_dec 的纪录直接放在主题表 ibf_topics?

家园 因为每帖都可以送花扔草

主题表只是每个主题有一行记录,但一个主题可以有多个帖子,每个帖子有各自的花草数量,所以只能放在帖子表ibf_posts。

家园 我怎么觉得直接选送花送草数量就可以了呢?

$query = "SELECT DISTINCT(ibf_posts.author_id), ibf_topics.*,ibf_posts.rep_inc,ibf_posts.rep_dec FROM ibf_topics

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']."

家园 如果有字段来标记posts的楼层也行

只要选取顶楼的就行了

家园 是这样的

其实讨论版核心用的是现成的程序,需要什么功能里面没有自己再改,这样省心很多。

当然,基本的资料库架构我就保留原样了,主题帖和跟帖并没有分开(内容都在ibf_posts表里边),只是关于主题标题等资讯另有一个表,前者类似于你说的post_content表,后者类似于你说的post表。花花草草我整合在发帖表里面,反正也只是两栏。

除了这些,还有很多其他大大小小的表(会员资料、短信、讨论版、分类、等级设定、管理记录......)好几十个。

要是全部自己写,不知要写到什么时候,呵呵。

家园 这也是个办法

不过我还是用比较发帖时间与id的方式达到了同样效果。

如果重头开始设计的话你的建议更好,只是我那个讨论版已经在运作,有十来万留言,再改表结构有些麻烦。

家园 这倒是,能借鉴当然借鉴

论坛程序算是web程序当中复杂程度很高的了,现在开源的东西也多,没必要自己动手发明轮子了,说到这儿尤其佩服铁手了。给他的回复献朵花去。。。

家园 问题已经解决,感谢留言的朋友

最后写成这样了,透过比较发帖id和时间辨认哪个是首发帖,放弃原本‘标示使用者参予帖’的功能,不然没法拿LEFT JOIN一物两用。

$query = "SELECT ibf_posts.author_id, ibf_posts.post_date, ibf_posts.rep_inc, ibf_posts.rep_dec, ibf_topics.* FROM ibf_topics

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']."

全看树展主题 · 分页 下页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河