在codeigniter中加入四个表

Posted

技术标签:

【中文标题】在codeigniter中加入四个表【英文标题】:Join four tables in codeigniter 【发布时间】:2015-10-26 10:05:50 【问题描述】:

我有四个表,如下所示

列表:

------------------------------------------------------------------------------------------------
| 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.netsee this *** question在列表表中 list_id 是主键,我知道使用自动增量是最好的,但我的要求是这样的。 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    |
----------------------------------------------------------------

cmets:

-------------------------------------------------------------------------
|.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 的视图计数,例如 cmets。

我尝试使用来自 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);

我得到了我想要的,但是如果我没有任何 cmets 或视图或喜欢,这种查询方式会失败(返回 null)。

【问题讨论】:

给出这些表的主键和关系。 我没有维护任何关系,只是试图加入 list_id 上的表 你好,downvoter,我希望得到最少的解释或我做错了什么 【参考方案1】:

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

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

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

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

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

Fiddle Demo

编辑有 0 个赞/查看和 cmets 的帖子

使用具有 0 个喜欢/视图和 cmets 的内部联接帖子将不会被返回,您需要左联接,您可以看到更新的演示,使用活动记录,您可以构建如下查询,定义联接类型(左/内/右) 在join() 函数的第三个参数中

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

Updated Demo

【讨论】:

@M Khalid Junaid 编辑了我的问题,我得到了我想要的,但是如果我没有任何 cmets 或视图或喜欢,这种查询方式会失败(返回 null)。 @saikiran 我已经根据您提供的数据集发布了答案,是的,使用带有 0 个赞/视图的内部连接帖子和 cmets 将不会返回您使用左连接,您可以在此处查看 demo 和使用活动记录->join ( 'likes li', 'l.sno = li.list_id','left') 如果需要这个答案我可以更新我的答案 是的,请使用左连接更新您的答案,我会按照承诺奖励您并感谢您的回答:) 我在列表中没有 s.no,我想知道使用 PHP 的 UUID 是个好主意。查看我提供的参考链接 @saikiran 你也可以使用mysqlUUID()函数把它留给mysql,这样它将是数据库的东西,只需从php执行查询,主键把它留给mysql【参考方案2】:

如果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 ();

【讨论】:

【参考方案3】:

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

你有一个经典的交叉产品。 JOIN 操作发生了什么,Likes 中的每个匹配行都与Views 中的每个匹配行“匹配”。如果Views 中有 3 个匹配行,Likes 有 3 个匹配行,您将返回 3x3 行。


您的数据库设计看起来不错。

问题在于生成的 SQL 查询。

要修复查询,要么

避免生成叉积计算不同的行数*

为避免交叉积,请勿将JOINLikesViews 表同时使用。作为替代方案,您可以避免连接操作,而是使用 SELECT 列表中的相关子查询...

 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 ... 

或者,如果您确实使用 JOIN 操作并生成叉积,则使用类似 COUNT(DISTINCT pk) 的表达式获取唯一行的计数,因此您不会多次计算同一行。

  SELECT list.*
       , COUNT(DISTINCT v.`s.no`) AS count_views
       , COUNT(DISTINCT l.`s.no`) AS count_likes

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

    FROM list
    LEFT JOIN views v ON v.list_id = list.list_id
    LEFT JOIN likes l ON l.list_id = list.list_id

一旦您了解了 MySQL 对代码当前生成的 SELECT 语句的作用,只需找出一条 SQL 语句即可返回您想要的结果。

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

【讨论】:

【参考方案4】:
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'

【讨论】:

【参考方案5】:

请更改您的查询以获得正确的计数,如下所示。

    $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 ();

【讨论】:

user_id在views和cmets中不一样,点赞@shanusingh 仅按列表和 cmets、likes、views 中常见的那些字段进行分组,并且应该是唯一的,或者将列表表 id 作为列放在每个其他表中,然后按该 id 分组 我修改了答案,请检查, 这没有给我正确的计数 然后更改您的表 cmets、likes、views 并添加列表表的一个主键列,然后在 group by 中使用该列【参考方案6】:

如果您害怕连接过多,请尝试使用 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,...));

【讨论】:

以上是关于在codeigniter中加入四个表的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mysql 和 Codeigniter 连接 4 个表

如何在 Codeigniter 中加入三个表

在 codeigniter 中加入超过 2 个数据库表错误:1066

如何根据codeigniter中的时间戳获取数据?

SQL 语句/Codeigniter 预约

MySQL CodeIgniter 中的数据库结构 Phpmyadmin