MySQL select 来自具有多个 where 子句和 find_in_set 的多个表

MySQL select from multiple tables with multiple where clauses and find_in_set

我在尝试使用 MySQL 查询避免部分重复结果时遇到问题。我承认我是 MySQL 的新手,但我从对 SO 的研究中了解到,我即将在下面为您展示的模式绝对可以用更好的方式完成(linked_users 列用户 table 应该是一个单独的 table)。但是,我现在无法更改它的设置方式。

我正在尝试 return 分配给 t2 中每个项目的用户 ID 的用户名或链接到这些用户的用户的用户名。但是,查询是 returning 每个项目的两组名称。我认为这种情况正在发生,因为它正在搜索它们两次,并且我试图阅读 this tutorial 关于 returning 来自多个 tables 的多个值,但我似乎无法让我全神贯注于 JOINS 和 UNIONS 等等。

我的问题有两个:

  1. 如何在不更改数据库设置方式的情况下解决此问题?
  2. 应如何更改数据库以更好地允许将来进行此类查询?

感谢您的宝贵时间。

架构:

create table users (user_id int, user_name varchar (55), linked_users varchar (55));
insert into users( user_id, user_name, linked_users)values(1, 'user1', '2,154,4,45');
insert into users( user_id, user_name, linked_users)values(2, 'user2', '13,1,200');
create table t2 (t2_id int, user_id int);
insert into t2( t2_id, user_id)values(1, 2);
insert into t2( t2_id, user_id)values(2, 1);
insert into t2( t2_id, user_id)values(3, 1);
insert into t2( t2_id, user_id)values(4, 2);
insert into t2( t2_id, user_id)values(5, 3);

查询:

SELECT t.*, u.user_name 
FROM t2 t, users u 
WHERE t.user_id = u.user_id
OR find_in_set(t.user_id, u.linked_users) > 0

Fiddle: http://sqlfiddle.com/#!9/c5540/10

您在同一个 table 中有多对多关系。一个用户可能有多个链接用户,一个用户可能是多个用户的链接用户。为了表示您需要一个额外的 table,您可以调用 linked_users,用两列定义:

user_id int foreign key to user_id in users table
linked_user_id int foreign key to user_id in users table

这个table的主键应该是user_id和linked_user_id

现在,假设您有用户 1 到 10,其中 1 个有 5、6、8 个链接用户,3 个有 1、6、10 个链接用户。你应该插入

1, 5
1, 6
1, 8
3, 1
3, 6
3, 10

在 linked_users 中。您的查询变为:

select u1.*, u2.*
from users u1 inner join linked_users lu on u1.user_id = lu.user_id
inner join users u2 on lu.linked_user_id = u2.user_id

如果你必须坚持你的设计

select u1.*, u2.*
from users u1 inner join users u2 on
find_in_set(u2.user_id, u1.linked_users) > 0

您绝对应该更改 table 的结构。正确的结构将使用两个 table,一个用于实体 ("users"),另一个用于它们之间的关系:

create table users (
    user_id int not null primary key auto_increment,
    user_name varchar(55)
);

create table userlinks (
    user_id int not null references users(user_id),
    linked_user_id int not null references users(user_id)
);

创建 table t2 ( t2_id 整数, user_id int not null references users(user_id) );

你的结构有几个明显的缺陷:

  • 您正在将整数值存储为它们的字符串表示形式。
  • 您将列表存储在字符串中,SQL 对逗号分隔列表的支持很少。
  • 您没有定义主键或外键。

使用此结构,您可以使用 exists:

获取给定 "t" 值的用户列表,没有重复且没有 distinct
select u.user_id
from users u cross join
     (select user_id from t2 where t2.tid = 1) t
where u.user_id = t.user_id or
      exists (select 1
              from ul
              where ul.user_id = t.user_id and
                    u.user_id = ul.linked_user_id
             );

查询说:"Get all the users where the user id matches the corresponding id in t2 or the user is linked to the user_id in t2."

请注意,您还可以通过以下方式对您的结构进行此操作:

select u.user_id
from users u cross join
     (select user_id from t2 where t2.tid = 1) t
where u.user_id = t.user_id or
      find_in_set(u.user_id,
                  (select u.linked_users from users u2 where u2.user_id = t.user_id)
                 ) > 0;

感谢 Gordon 和 Tarik 的回复。我尝试了你在我的 fiddle 中提供的代码,但无法提取 t2 信息,所以在进一步研究之后,我发现这个查询解决了我遇到的问题:

SELECT t2.*, u.user_name 
FROM users u, t2 t 
WHERE t.user_id = u.user_id 
AND (t.user_id = '$user_id' 
     OR t.user_id IN 
        (SELECT u2.user_id 
         FROM users u2 
         WHERE find_in_set('$user_id', u2.linked_users)
        )
    )

同样,我知道这不是最佳方式,但由于我无法更改结构,因此可以达到目的。