在codeigniter中加入四个表

时间:2015-08-04 06:11:33

标签: php mysql database codeigniter join

我有四张桌子,如下面

编目:

------------------------------------------------------------------------------------------------
| list_id                              |user_id | name | category | fees | details |created_on |
------------------------------------------------------------------------------------------------
| 90cc57a4-f782-4c57-ac98-1965c57ece57 |user 100 |satwik| music   | 500  | dummy   |2015-08-02 |
------------------------------------------------------------------------------------------------

将我的list_id从随机字符串更改为UUID。
from this comment on php.net
see this stackoverflow question
在列表中,list_id是主键,我知道使用autoincreament是最好的,但我的要求是这样的。并且s.no是其余表格的主键。

我需要从PHP端生成随机密钥,因为要在会话中设置list_id并避免在会话中设置list_id的另一个查询。 喜欢:

----------------------------------------------------------------
|.sno | list_id                              | user_id | likes |
----------------------------------------------------------------
| 1   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user110 |  1    |
----------------------------------------------------------------
| 2   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user215 |  1    |
----------------------------------------------------------------
| 3   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user200 |  1    |
----------------------------------------------------------------

注释:

-------------------------------------------------------------------------
|.sno | user_id | list_id                              | comment         |
-------------------------------------------------------------------------
|  1  | user 205| 90cc57a4-f782-4c57-ac98-1965c57ece57 | dummy comment   |
-------------------------------------------------------------------------

查看:

----------------------------------------------------------------
|.sno | list_id                              | user_id | views |
----------------------------------------------------------------
| 1   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user110 |  2    |
----------------------------------------------------------------
| 2   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user215 |  1    |
----------------------------------------------------------------
| 3   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user200 |  1    |
----------------------------------------------------------------

我正在尝试从列表表中获取用户ID user100的列表

并且需要从我拥有的各种表格中获取用户列表ID的评论次数。

我尝试使用codeigniter

中的此查询
 $this->db->select ( 'list.*,count(v.views) as views,count(l.likes) as likes,count(c.comment) as comments' )
                 ->from ( 'listings as list' )
                 ->join ( 'views v', 'v.list_id = list.list_id')
                 ->join ( 'likes l', 'l.list_id = list.list_id')
                 ->join ( 'comments c', 'c.list_id = list.list_id');
$this->db->where ( 'list.user_id', $user_id);
$query = $this->db->get ();

我收到了错误的观点和喜欢和评论。

这个数据库设计是好还是我需要改变任何东西。我对使用连接的兴趣不大,请帮助我。

修改

我从下面的答案中尝试了这个查询

$this->db->select ( 'l.*,count(distinct v.s_no) as views,count(distinct li.s_no) as likes,count(distinct c.s_no) as comments' ,false)
    ->from ( 'listings as l' )
    ->join ( 'likes li', 'l.list_id = li.list_id')
    ->join ( 'comments c', 'l.list_id = c.list_id')
    ->join ( 'views v', 'l.list_id = v.list_id')
    ->where ( 'l.user_id', $id);

我得到了我想要的东西,但如果我没有任何评论,观点或喜欢,这种查询方式会失败(返回null)。

6 个答案:

答案 0 :(得分:5)

考虑到您的结构,您的每个表都应该有一个字段定义为primary key,并且列表(关联,视图和注释)的关联应该与该关键字相关联foreign key我期望{ {1}}字段被定义为每个表的主键,因此在您的情况下{Like}}列中的like视图和注释将引用列表表格,其中自动生成的列表ID为1,2,3所以然后,不再需要列表中的sno列,同样的情况将适用于您的用户表及其自动生成的用户ID现在您正在使用多个连接的查询部分,以便 @FuzzyTree 提到的交叉产品,并且对结果集进行聚合会给你带来比预期更多的错误结果,因此你需要一个独特的计数,这就是为什么我已经为表定义主键而不是计算{{1}对于喜欢和评论,计算不同的list_id

list_id

使用活动记录,您可以编写类似

的查询
v.views

根据您提供的数据集列表1有3个赞,3个浏览和1个评论,您可以找到上述查询的附加演示,您还可以找到foreign keys and cascading的更新表定义(将有助于维护关系)< / p>

Fiddle Demo

编辑包含0个喜欢/观看和评论的帖子

使用带有0个赞/视图和评论的内部联接帖子将不会返回此项您需要左联接您可以看到更新的演示并使用活动记录您可以构建如下的查询,定义连接类型(左/内/右) )在v.sno函数的第三个参数

select l.*,
count(distinct v.sno) as views,
count(distinct li.sno) as likes,
count(distinct c.sno) as comments
from listings l
join likes li on(l.sno = li.list_id)
join comments c on(l.sno = c.list_id)
join `views` v on(l.sno = v.list_id)
where l.user_id = 'user100'
group by l.sno

Updated Demo

答案 1 :(得分:4)

如果user_id不是likescommentsviews的唯一身份,那么在进行多次加入时,您最终会得到一个交叉产品,这会夸大您的计数。因为您只查询一个user_id,所以子查询可能是最好的方法。

请记住将第二个参数设置为selectfalse,以便codeigniter不会尝试转义子查询。

$this->db->select ( 'list.*, 
    (select count(*) from views v where v.user_id = list.user_id) as views,
    (select count(*) from likes l where l.user_id = list.user_id) as likes,
    (select count(*) from comments c where c.user_id = list.user_id) as comments',false)->from ( 'listings as list' );
$this->db->where ( 'list.user_id', $user_id);
$query = $this->db->get ();

答案 2 :(得分:1)

如果仔细查看“错误”值,并查看导致膨胀值的各个行,您会发现您正在多次计算相同的行数。 (使用内部联接,如果其中一个表的行匹配为零,则不会返回该行。)

你有一个经典的交叉产品。 JOIN操作发生了什么,data-ng-repeat="stackoverflow in overflows| filter:stackoverflow.property.status===status.value" 的每个匹配行都与stackoverflow.property.status的每个匹配行“匹配”。如果Likes中有三个匹配的行,Views中有三个匹配的行,则会返回3x3行。

您的数据库设计看起来没问题。

生成的SQL查询就是问题所在。

要修复查询,

要么避免生成交叉产品,要么计算不同的行*

要避免跨产品,请不要Views同时使用LikesJOIN表。作为替代方法,您可以避免连接操作,而是使用SELECT列表中的相关子查询...

Likes

或者,如果您使用JOIN操作并生成交叉产品,则使用类似Views的表达式获取唯一行的计数,因此您不会多次计算同一行。

 SELECT list.*
      , (SELECT COUNT(1) FROM views v WHERE v.list_id = list.list_id) AS count_views
      , (SELECT COUNT(1) FROM likes l WHERE l.list_id = list.list_id) AS count_likes
   FROM list  
  WHERE ... 

要允许返回计数为零的行,您需要使用外连接:

COUNT(DISTINCT pk)

一旦你理解了MySQL正在使用你的代码当前生成的SELECT语句做什么,只需要找出一个能够返回你想要的结果的SQL语句。

获得返回预期结果的SQL语句后,只需让CodeIgniter运行SQL语句即可。

答案 3 :(得分:0)

select a.list_id,a.user_id,a.name,a.category,a.fees,a.details,a.created_on,
(select sum(likes) from  Likes where user_id=a.user_id) "total likes",
(select count(*) from  comments where user_id=a.user_id) "total comments",
(select sum(views) from  views  where user_id=a.user_id) "total views",
from Listings as a
where a.user_id ='user 100'

答案 4 :(得分:-1)

请更改您的查询以获得正确的计数。

    $this->db->select ( 'list.*,count(v.views) as views,count(l.likes) as likes,count(c.comment) as comments' )
             ->from ( 'listings as list' )
             ->join ( 'comments c', 'c.list_id = list.list_id')
             ->join ( 'views v', 'v.list_id = list.list_id')
             ->join ( 'likes l', 'l.list_id = list.list_id');

        $this->db->where ( 'list.user_id', $user_id);
        $this->db->group_by( 'v.list_id');
        $this->db->group_by( 'l.list_id');
        $this->db->group_by( 'c.list_id');
      $query = $this->db->get ();

答案 5 :(得分:-1)

如果您害怕加入过多的连接,请尝试SQL IN语句。做点什么;

// You can include query binding if you like
$sql = SELECT column_name(s)
FROM table_name
WHERE column_name IN (SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...) WHERE SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...));