0

我在尝试使用 MySQL 查询避免部分重复结果时遇到问题。我承认我是 MySQL 的新手,但我从对 SO 的研究中了解到,我将在下面为您布置的架构肯定可以做得更好(users 表的linked_users 列应该是一个单独的表)。但是,我现在无法更改它的设置方式。

我正在尝试返回分配给 t2 中每个项目的用户 ID 的用户名或链接到这些用户的用户的用户名。但是,该查询为每个项目返回两组名称。我认为这种情况正在发生,因为它正在搜索它们两次,并且我试图阅读关于从多个表返回多个值的本教程,但我似乎无法围绕 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

小提琴: http ://sqlfiddle.com/#!9/c5540/10

4

3 回答 3

1

您在同一个表中有多对多关系。一个用户可能有许多链接用户,并且一个用户可能是多个用户的链接用户。为了表示您需要一个额外的表,您可以调用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

该表的主键应该同时是 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
于 2015-05-16T00:56:16.333 回答
1

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

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

创建表 t2 ( t2_id int, user_id int not null 引用 users(user_id) );

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

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

使用此结构,您可以使用以下命令获取给定“t”值的用户列表,不重复且不包含 a distinctexists

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

查询说:“获取用户 id 与相应 id in 匹配t2或用户链接到user_idin的所有用户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;
于 2015-05-16T01:22:46.607 回答
1

感谢 Gordon 和 Tarik 的回复。我尝试了你在我的小提琴中提供的代码,但无法提取 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)
        )
    )

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

于 2015-05-16T20:11:56.140 回答