关于我的问题的更多背景知识。我有一个"追随者"我的网站上的侧边栏,用户可以关注其他用户。问题是,目前此侧栏中显示的用户还可以包括他们已经关注的用户。我想修改功能,这样就不再发生了。这是我目前使用的模型函数......
public function get_oldest($limit = 10, $user_id)
{
$this->db
->select($this->db->dbprefix('profiles').'.*, g.description as group_name, users.*')
->join('groups g', 'g.id = users.group_id')
->join('profiles', 'profiles.user_id = users.id', 'left')
->group_by('users.id');
$this->db->order_by('users.created_on', 'ASC');
$this->db->limit($limit);
$results = $this->db->get('users')->result_array();
return $results;
}
这是控制器功能......
function get_oldest() {
$this->load->model('user_account/user_account_m');
$limit = $this->attribute('limit');
$user_id = $this->current_user->id;
$users = $this->user_account_m->get_oldest($limit, $user_id);
return $users;
}
sql数据库中的" Follower"(default_follow)表具有以下结构......
id =关注事件的身份
follower_id =正在执行以下操作的人的user_id
followed_id =被关注者的user_id
sql数据库中的" Profile"(default_profiles)表具有以下结构......
user_id
display_name
first_name
last_name
我知道我需要以某种方式使用当前用户的ID来实现这一点,我只是很难弄清楚如何使用。在此先感谢您的帮助。
答案 0 :(得分:2)
在sql中设置差异的一种方法是EXCEPT关键字。我在sqlfiddle上放了一个玩具渲染: http://sqlfiddle.com/#!6/2308a/6
SELECT distinct user_id
FROM users
EXCEPT
SELECT followed_id
FROM follow
WHERE follower_id = <idhere>
顶级sql将获取系统中的所有user_id。底部将抓取当前用户关注的所有人,并且EXCEPT关键字将应用设置差异以向您提供当前用户尚未关注的所有用户。
答案 1 :(得分:1)
您正在寻找的功能称为子查询。
在SQL中,您的CodeIgniter ActiveRecord查询大致翻译为:
SELECT profiles.*, g.description as group_name, users.*
INNER JOIN groups g ON g.id = users.group_id
LEFT JOIN profiles ON profiles.user_id = users.id
GROUP BY users.id
ORDER BY users.created_on;
要过滤掉现有的关注者,我们将为使用IN关键字和子查询的子句添加WHERE子句:
SELECT profiles.*, g.description as group_name, users.*
INNER JOIN groups g ON g.id = users.group_id
LEFT JOIN profiles ON profiles.user_id = users.id
WHERE users.id NOT IN (SELECT follower_id FROM default_follow WHERE followed_id = ?)
GROUP BY users.id
ORDER BY users.created_on;
?表示一个查询参数,在您的情况下,它将是登录用户的ID。
转换回CodeIgniter,你有几个选择:
1)将NOT IN子句直接写入CodeIgniter的“where”函数调用,连接用户ID。
$this->db
->select($this->db->dbprefix('profiles').'.*, g.description as group_name, users.*')
->join('groups g', 'g.id = users.group_id')
->join('profiles', 'profiles.user_id = users.id', 'left')
->where('users.id NOT IN (SELECT follower_id FROM default_follow WHERE followed_id = '.$user_id.')', NULL, FALSE)
->group_by('users.id');
2)将子查询分解为单独的查询,并在第二个查询中使用结果:
$this->subquery->select('follower_id')
->where('followed_id', $user_id);
$followers = $this->subquery->get('default_follow')->result_array();
$this->db
->select($this->db->dbprefix('profiles').'.*, g.description as group_name, users.*')
->join('groups g', 'g.id = users.group_id')
->join('profiles', 'profiles.user_id = users.id', 'left')
->where_not_in('users.id', $followers)
->group_by('users.id');
选项1很好,因为它允许数据库完成所有工作,但是根据$ user_id来自哪里,您可能会打开SQL注入攻击。您希望提前对输入进行消毒。
选项2对SQL注入是安全的,但迫使PHP完成一些工作。它不会那么快,特别是对于拥有大量粉丝的用户。有些数据库对可以包含在显式IN子句中的元素数量有限制(特别是,Oracle将你限制为1000),但看起来你正在使用没有这种限制的mySQL。
我希望有一个选项三,但CodeIgniter的ActiveRecord功能不提供对子查询的原生支持(尚未)。鉴于上述选项,我将采用选项1并确保自己防止SQL注入。
这是使用CodeIgniter ActiveRecord查询的一个不错的参考:
http://ellislab.com/codeigniter/user-guide/database/active_record.html