【问题标题】:MySQL - Like + JOINMySQL - 喜欢 + 加入
【发布时间】:2012-09-07 21:43:35
【问题描述】:

我想在我的数据库中搜索一个用户,并为每个用户在另一个表上进行 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`;

实际上,如果搜索用户显示为fan_id 并且搜索用户显示为idol_id 或相反,我想进入relations。 但是当我使用第一个查询搜索用户时,我有 2 行,2 个用户(ids = 80 & 125)。对于第二个查询,我只有 1 行(id = 80),但 relations 显示 100:80;100:125 表示我有一半的查询工作......

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

感谢您的帮助。

【问题讨论】:

  • 真的很难理解你真正想要什么。 fan_id 是检查自己与其他用户之间关系的用户的 id 吗?你想让他们看看被搜索的用户是正在搜索的用户的粉丝还是偶像?你为什么要连接这些结果?为什么不只是两栏,一栏是偶像,一栏是粉丝,分别是真还是假?
  • 是的,很抱歉解释得不好。实际上,我想搜索用户,并与正在搜索用户的用户建立关系。然后在 PHP 中,我只需要计算关系(2 表示相互关注,1 表示我必须检查谁在关注)
  • 我已经编辑了我的答案以包含我为您提出的另一个查询。

标签: mysql join concat group-concat


【解决方案1】:

使用标准 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

【讨论】:

  • 我只是好奇,但我从未听说过旧式 ANSI SQL-86 JOIN 语法被称为 omega-join。这个词是从哪里来的?
  • 我不知道我是否在任何地方读过它。但是我曾经工作过的一家老式甲骨文商店的一些同事这样称呼它。它可能来自左连接的a.id = b.id(+) 语法。
  • @OllieJones 按顺序:1) 完成此操作后,我将寻找 FULLTEXT。 2)backtips是为了我自己的可读性,如果有错,我会删除它们。 3)我不知道 GROUP_CONCAT 和 GROUP BY T_T 。 4) 你说得对,我的意思是idol_id。 100 将是正在搜索另一个用户的 user_id。最终)您的查询与我要查找的内容接近。但是我们现有的一个用户没有显示,因为100 和第二个用户之间没有交互。我需要一个默认值。非常感谢。
【解决方案2】:

这是基于我认为您的目标的猜测:

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=80where idol_id=80 需要设置为正在搜索的用户的正确 id,where id=100 可以替换为查找执行搜索的用户的位置。或者您可以删除所有三个并获取每个人与彼此的关系列表。

---编辑---

Sqlfiddle

此查询提供的详细信息较少,但仅搜索一次朋友和用户一次;具体来说,它不再保存偶像和粉丝列中的 id,而是这些列要么为 1,要么为空。 1表示该用户是其他用户的用户,因此用户125搜索用户100并拥有fan - 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 子句可以随心所欲地填充。

【讨论】:

  • 嘿!我在您的查询和上一个查询之间进行了混合,唯一的问题是当没有结果时,它不是='',因为我仍然只有一行(2 个用户的用户名是 LIKE %max%)。还是谢谢你:)
  • @Max13 很抱歉,但我不太明白这个问题。如果没有关系匹配则relations=null2 users has the username LIKE %max% 和它有什么关系?您是说如果您在用户进行搜索时获得多个结果,您会得到错误的结果?如果您仍然有问题并希望我帮助您,我会继续帮助您,所以请告诉我。您是否也考虑过使用 3 列、关系计数(2 相互跟随,1 是粉丝或偶像,0 都不是),然后是可以为空或具有 id 的粉丝和偶像列。
  • 是的!这几乎就是我要找的。今天我做了 2 个不同的查询,但是如果我使用你的,通过搜索 (username LIKE '%user%'),你的查询不会比 2 个不同的更慢吗?我想将它们结合起来(如您的查询),但我害怕速度(案例 + 2 个连接)?感谢您的帮助。
  • @Max13 如果没有对大量数据进行测试,我很难说,但这是可能的。我曾经测试过两个查询,其中更复杂的一个会让我的生活变得更轻松,但它非常慢,所以我没有使用它。在我看来,有时使用 PHP 来获得你想要的结果是正确的方法。查询因为它搜索了两次朋友和一次用户,case 只被应用了一次,所以不应该有太大的差异,并且数据加入的数量相对较少,因为它被过滤掉了我认为是wheres。
  • 我已经检查了你的第二个 sqlfiddle,它很像我需要的,但是除了有 3 列(fansidolsrelation)没有办法获得CONCAT 的实际关系?喜欢80:100;100:80 吗?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-04
  • 2019-07-03
  • 2014-03-30
  • 2012-03-17
  • 2010-11-10
相关资源
最近更新 更多