如何在MySQL5.7中实现cte功能?

huus2vyu  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(569)

我有一个usersearch表,应该用于用户的快速子字符串搜索。此功能用于在键入用户名或名称时自动完成搜索。但是,我感兴趣的查询将只显示来自搜索者跟踪的用户子集的匹配项。这可以在userrelationship表中找到。

  1. USERSEARCH
  2. -----------------------------------------------
  3. user_id(FK) username_ngram name_ngram
  4. 1 "AleBoy leBoy eBoy..." "Ale le e"
  5. 2 "craze123 raze123 ..." "Craze raze aze ze e"
  6. 3 "john1990 ohn1990 ..." "John ohn hn n"
  7. 4 "JJ_1 J_1 _1 1" "JJ"
  8. USERRELATIONSHIP
  9. -----------------------------------------------
  10. user_id(FK) follows_id(FK)
  11. 2 1
  12. 2 3

当有人刚刚输入“al”(不考虑用户关系)时,会进行这样的查询:

  1. SELECT * FROM myapp.usersearch where username_ngram like 'Al%'
  2. UNION DISTINCT
  3. SELECT * FROM myapp.usersearch where name_ngram like 'Al%'
  4. UNION DISTINCT
  5. SELECT * FROM myapp.usersearch
  6. WHERE MATCH (username_ngram, name_ngram) AGAINST ('Al')
  7. LIMIT 10

这是惊人的快,因为现有的索引用户名,名称和全文(用户名,名称)。但是,在我的应用程序上下文中,我需要将搜索限制为搜索者跟踪的用户。我想将“myapp.usersearch”表替换为“myapp.usersearch”表的子集,该表只包括搜索者正在跟踪的用户。以下是我的尝试:

  1. WITH
  2. --Part 1, restrict the USERSEARCH table to just the users that are followed by searcher
  3. tempUserSearch AS (SELECT T1.id, T2.username_ngram, T2.name_ngram FROM
  4. (SELECT follows_id FROM myapp.userrelationship WHERE user_id = {user_idOfSearcher} ) AS T1
  5. LEFT JOIN myapp.usersearch AS T2 ON T2.user_id = T1.follows_id)
  6. SELECT * FROM tempUserSearch where username_ngram like 'Al%'
  7. UNION DISTINCT
  8. SELECT * FROM tempUserSearch where name_ngram like 'Al%'
  9. UNION DISTINCT
  10. SELECT * FROM tempUserSearch
  11. WHERE MATCH (username_ngram, name_ngram) AGAINST ('Al')
  12. LIMIT 10

不幸的是,MySQL5.7不支持cte with子句。
是否有任何方法可以在所有后续子查询中引用查询的第1部分,而无需重新查询该用户的用户id(在MySQL5.7中)
更新:
在MySQL5.7中真的没有办法多次引用查询吗?在我看来,这是任何db的一项基本任务,因此似乎有些不对劲。
为什么不:“x在a、b或c上连接y”?子字符串查询的速度取决于以下索引:

  1. index(username_ngram)
  2. index(name_ngram)
  3. FULLTEXT(username_ngram, name_ngram)

使用或不受任何索引的帮助。

8e2ybdfx

8e2ybdfx1#

MySQL5.7不支持公共表表达式;这个 WITH 语法仅在版本8.0中可用。
由于现有查询运行速度很快,因此在外部查询中进行筛选可能是可行的解决方案:

  1. SELECT ur.id, ng.username_ngram, ng.name_ngram
  2. FROM myapp.userrelationship ur
  3. INNER JOIN (
  4. SELECT * FROM myapp.usersearch WHERE username_ngram LIKE 'Al%'
  5. UNION DISTINCT
  6. SELECT * FROM myapp.usersearch WHERE name_ngram LIKE 'Al}%'
  7. UNION DISTINCT
  8. SELECT * FROM myapp.usersearch WHERE MATCH (username_ngram, name_ngram) AGAINST ('Al')
  9. ) ng ON ng.user_id = ur.follows_id
  10. WHERE ur.user_id = {user_idOfSearcher}
  11. ORDER BY ??
  12. LIMIT 10

笔记:
我转过身来 LEFT JOIN 到一个 INNER JOIN 因为我认为这更接近你想要的(如果它不符合你的要求,你可以把它改回去)
你需要一个 ORDER BY 条款 LIMIT ,否则当结果集中的行数超过10行时,结果是不确定的

展开查看全部

相关问题