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 等等。
我的问题有两个:
- 如何在不更改数据库设置方式的情况下解决此问题?
- 应如何更改数据库以更好地允许将来进行此类查询?
感谢您的宝贵时间。
架构:
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
您在同一个 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)
)
)
同样,我知道这不是最佳方式,但由于我无法更改结构,因此可以达到目的。
我在尝试使用 MySQL 查询避免部分重复结果时遇到问题。我承认我是 MySQL 的新手,但我从对 SO 的研究中了解到,我即将在下面为您展示的模式绝对可以用更好的方式完成(linked_users 列用户 table 应该是一个单独的 table)。但是,我现在无法更改它的设置方式。
我正在尝试 return 分配给 t2 中每个项目的用户 ID 的用户名或链接到这些用户的用户的用户名。但是,查询是 returning 每个项目的两组名称。我认为这种情况正在发生,因为它正在搜索它们两次,并且我试图阅读 this tutorial 关于 returning 来自多个 tables 的多个值,但我似乎无法让我全神贯注于 JOINS 和 UNIONS 等等。
我的问题有两个:
- 如何在不更改数据库设置方式的情况下解决此问题?
- 应如何更改数据库以更好地允许将来进行此类查询?
感谢您的宝贵时间。
架构:
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
您在同一个 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
:
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)
)
)
同样,我知道这不是最佳方式,但由于我无法更改结构,因此可以达到目的。