我想在我的数据库中搜索用户,并为每个用户在另一个表上创建一个JOIN。这是我的表格:
USERS
:id
,firstname
,lastname
,[...] - 包含用户数据
FRIENDS
:fan_id
,idol_id
,[...] - 哪个用户关注哪个用户
这是我的搜索查询,经典:
SELECT `id`, `username`, `firstname`, `lastname`, `lang`, `twitter`, `facebook`, `picture`, `regdate`
FROM `users`
WHERE `username` LIKE ?
OR `email` LIKE ?
OR `firstname` LIKE ?
OR `lastname` LIKE ?
OR `twitter` LIKE ?
OR `facebook` LIKE ?
ORDER BY `username`;
所以现在,我想要一个获取朋友表,包含搜索到的用户和询问此用户的用户之间的关系。
以下是我的想法:
SELECT `id`, `username`, `firstname`, `lastname`, `lang`, `twitter`, `facebook`, `picture`, `regdate`,
GROUP_CONCAT(
CONCAT_WS(':', `fan_id`, `idol_id`) SEPARATOR ';'
) AS relations
FROM `friends`, `users`
WHERE (`username` LIKE ?
OR `email` LIKE ?
OR `firstname` LIKE ?
OR `lastname` LIKE ?
OR `twitter` LIKE ?
OR `facebook` LIKE ?)
AND (
(`fan_id` = 100 AND `idol_id` = `id`)
OR
(`fan_id` = `id` AND `idol_id` = 100)
)
ORDER BY `username`;
实际上,如果搜索到的用户显示为relations
而搜索用户显示为fan_id
或相反,我希望进入idol_id
。
但是,当我搜索具有第一个查询的用户时,我有2行,2个用户(ids = 80
& 125
)。对于第二个查询,我只有一行(id = 80
),但relations
显示100:80;100:125
,表示我有一半的查询工作...
有关信息,如果没有(relations
),我也希望得到一个结果,所以我尝试了IFNULL(..., 0)
,但仅此而已。
感谢您的帮助。
答案 0 :(得分:3)
这是基于我认为你的目标的猜测:
select users.id,users.firstname,
case
when CONCAT_WS(';',t1.fans,t2.idols)='' then null
else CONCAT_WS(';',t1.fans,t2.idols)
end as relations
from users left join
(
select CONCAT_WS(':',fan_id,idol_id) as fans,idol_id
from friends
where fan_id=80
) as t1
on users.id=t1.idol_id
left join
(
select CONCAT_WS(':',fan_id,idol_id) as idols,fan_id
from friends
where idol_id=80
) as t2
on users.id=t2.fan_id
where id=100
Sqlfiddle是ID为100且正在搜索ID为80的用户的结果。
where fan_id=80
和where idol_id=80
需要设置为正在搜索的用户的正确ID,where id=100
可以替换为查找用户进行搜索的人员。或者你可以删除这三个并获得每个人彼此关系的列表。
--- --- EDIT
此查询提供的细节较少,但仅通过朋友搜索一次,用户只搜索一次;特别是它不再保存idol和fan列中的id,而是这些列为1或null。 1表示用户是另一个用户的用户,因此用户125搜索用户100并且具有fan - null | idol - 1
,这意味着他们不是用户100的粉丝,但他们是用户100的偶像。关系列为在我之前的评论中建议,对于粉丝和偶像都是2,对于其中一个是1,或者两者都不是。
select users.id,users.firstname,sum(t1.fan) as fan,sum(t1.idol) as idol,
case
when t1.fan is null and t1.idol is null then null
else count(*)
end as relations
from users
left join
(
select fan_id,idol_id,
case when fan_id=100 then 1 end as idol,
case when idol_id=100 then 1 end as fan
from friends
where fan_id=100 or idol_id=100
) as t1
on users.id=t1.fan_id or users.id=t1.idol_id
where firstname like '%user1%'
group by id
您必须更改所搜索用户的ID的所有100个地方。底部的where子句可以填充你想要的任何内容。
答案 1 :(得分:2)
使用标准JOIN
语法要比使用您正在使用的过时omega-join模型容易得多。
在多表查询中,您可能应该限定列名。
使用所谓的潜在客户表开始加入。在你的情况下,你想要每个用户一行,所以用它开始连接。
您的WHERE中的OR
条件的长级联将导致您的查询执行得非常糟糕。您可能需要考虑某种FULLTEXT(二进制模式)搜索。
反引号禁止可读性,除非表或列与保留字同名,否则不需要。
您在查询中有一个GROUP_CONCAT
汇总函数,但没有相应的GROUP BY
子句。你需要两者。 (有一些允许的语言快捷方式,其中GROUP BY
不是必需的,但是在调试时应避免使用这些快捷方式。)
我想弄清楚你的加入标准,但我不明白。我不明白id = 100有什么特别之处。但是,在你加入的第二部分,你是否有可能想要idol_id = 100
而不是fan_id = 100
?
(f.fan_id = u.id AND f.idol_id = 100)
对于你的项目,你所拥有的东西似乎不合乎逻辑。
我建议你试试这个:
SELECT u.id, u.username,
u.firstname, u.lastname,
u.lang, u.twitter, u.facebook,
u.picture, u.regdate,
GROUP_CONCAT(CONCAT_WS(':', f.fan_id, f.idol_id) SEPARATOR ';') AS relations
FROM users u
JOIN friends f ON (
(f.fan_id = 100 AND f.idol_id = u.id)
OR
(f.fan_id = u.id AND f.idol_id = 100)
)
WHERE u.username LIKE ?
OR u.email LIKE ?
OR u.firstname LIKE ?
OR u.lastname LIKE ?
OR u.twitter LIKE ?
OR u.facebook LIKE ?
GROUP BY u.id, u.username,
u.firstname, u.lastname,
u.lang, u.twitter, u.facebook,
u.picture, u.regdate
ORDER BY u.username