2

关于我的问题的更多背景信息。我的网站上有一个“关注者”侧边栏,用户可以在其中关注其他用户。问题是目前出现在这个侧边栏中的用户还可以包括他们已经关注的用户。我想修改函数,这样就不会再发生了。这是我目前使用的模型功能...

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 = 关注事件的id
follower_id = 进行关注的人的user_id
follow_id = 被关注的人的user_id

sql数据库中的“Profile”(default_profiles)表结构如下...

user_id
display_name
first_name
last_name

我知道我需要以某种方式使用当前用户的 id 才能让它工作,我只是很难弄清楚如何。提前感谢您的帮助。

4

2 回答 2

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 关键字将应用设置差异,为您提供当前用户尚未关注的所有用户。

于 2013-04-02T15:21:36.687 回答
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

于 2013-04-02T17:44:45.873 回答