2

我想在我的数据库中搜索一个用户,并为每个用户在另一个表上进行 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_idAND 搜索用户为idol_id或相反,我想进入。但是当我使用第一个查询搜索用户时,我有 2 行,2 个用户(ids = 80& 125)。对于第二个查询,我只有 1 行 (id = 80),但relations显示100:80;100:125我有一半的查询工作......

有关信息,如果没有 (in relations),我也想得到一个结果,所以我尝试IFNULL(..., 0)了但仅此而已。

谢谢您的帮助。

4

2 回答 2

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可以替换为查找执行搜索的用户的 wheres。或者您可以删除所有三个并获取每个人与彼此的关系的列表。

- -编辑 - -

Sqlfiddle

此查询提供的详细信息较少,但仅搜索一次朋友和用户一次;具体来说,它不再保存偶像和粉丝列中的 id,而是这些列要么为 1,要么为空。1 表示该用户是另一个用户的用户,因此用户 125 搜索用户 100 并且 hasfan - null | idol - 1这意味着他们不是用户 100 的粉丝,而是用户 100 的偶像。我之前的评论中建议的关系列要么是粉丝和偶像都是 2,要么是其中之一,要么是 1,或者两者都不为 0。

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 子句可以由您想要的任何内容填充。

于 2012-09-14T18:41:03.870 回答
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
于 2012-09-14T18:25:59.220 回答