在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 你也可以使用mysql的UUID()
函数把它留给mysql,这样它将是数据库的东西,只需从php执行查询,主键把它留给mysql【参考方案2】:
如果user_id
不是likes
、comments
或views
所独有的,那么在进行多次连接时,您最终会得到一个叉积,这会增加您的计数。因为您只查询一个 user_id,所以子查询可能是最好的方法。
记得将第二个参数设置为select
到false
,这样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 查询。
要修复查询,要么
避免生成叉积或计算不同的行数*
为避免交叉积,请勿将JOIN
与Likes
和Views
表同时使用。作为替代方案,您可以避免连接操作,而是使用 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 个表