MySQL自动完成排序问题
我的网站上有一个自动完成功能,用户可以在其中输入学校的课程。然后,它提供了一个类的下拉列表,其中包含他们在字段中某处输入的单词。 Classes 表包含字段 Class_ID、Term_ID、Department_Code、Course_Code、Class_Code、Course_Title、Instructor,这些字段均按用户输入的术语进行搜索。假设用户输入单词“international econ”。然后,它将在字段中搜索这两个术语,如下所示:
SELECT Class_ID, Department_Code, Course_Code, Class_Code, Course_Title, Instructor FROM Classes AND ((REPLACE(REPLACE(REPLACE(CONCAT(Department_Code, Course_Code, Class_Code), '-', ''), '(', ''), ')', '') LIKE '%international%' OR Instructor LIKE '%international%' OR Course_Title LIKE '%international%') AND (REPLACE(REPLACE(REPLACE(CONCAT(Department_Code, Course_Code, Class_Code), '-', ''), '(', ''), ')', '') LIKE '%econ%' OR Instructor LIKE '%econ%' OR Course_Title LIKE '%econ%')) LIMIT 10
关于此查询的两个快速注释 - 我执行 REPLACE() 和 CONCAT() 以便用户可以输入部门/课程/部分作为一个单元,例如 ECON-101 (一个部门和一个课程在一起)。另外,我还粘贴了一个大大简化的查询,其中省略了我当前的排序和分组方式。
然而我的问题涉及如何对结果进行排序。我希望与 Class_Code 匹配的条目返回到顶部,然后是 Course_Code,然后是 Dept,然后是 Course_Title,最后是 prof。换句话说,我希望结果按照用户在自动完成中提供的具体程度进行排序。如果他们知道 Class_Code,我希望它位于顶部。
我想不出一种不需要大量查询的方法来进行这种排序。到目前为止,我能想到的唯一方法是将每个术语与每个字段进行一堆 LIKE 比较别名,然后按这些别名进行排序。这相当于用户在自动完成中输入的字数的 5 倍。换句话说,这是一个巨大而丑陋的查询。
有没有一种简单、有效的方法来进行这种排序?如果有像 INSTR() 函数这样需要多个字符串进行搜索的东西,我可以轻松地将自动完成中的所有单词与每个字段进行比较,并始终对由该函数生成的 5 个别名进行排序。
欢迎任何意见,即使它是超出问题范围的一般性建议。然而,我想提前指出,我不愿意在这里使用 FULLTEXT 或 Sphinx 这样的搜索系统,因为我觉得它不适合像这样的非密集、快速查询。另外,我不愿意重组我的数据库。所以我想通过对我已有的内容进行良好的 MySQL 查询来完成此操作。
提前致谢..
I have an autocomplete on my site where a user enters a class at their school. It then provides a dropdown of Classes that have the words they entered somewhere in their fields. The Classes table has the fields Class_ID, Term_ID, Department_Code, Course_Code, Class_Code, Course_Title, Instructor which are all searched by the terms the user puts in. Suppose a use enters the words "international econ". It would then search these two terms in the fields as follows:
SELECT Class_ID, Department_Code, Course_Code, Class_Code, Course_Title, Instructor FROM Classes AND ((REPLACE(REPLACE(REPLACE(CONCAT(Department_Code, Course_Code, Class_Code), '-', ''), '(', ''), ')', '') LIKE '%international%' OR Instructor LIKE '%international%' OR Course_Title LIKE '%international%') AND (REPLACE(REPLACE(REPLACE(CONCAT(Department_Code, Course_Code, Class_Code), '-', ''), '(', ''), ')', '') LIKE '%econ%' OR Instructor LIKE '%econ%' OR Course_Title LIKE '%econ%')) LIMIT 10
Two quick notes on this query-- I do the REPLACE() and CONCAT() so that users can enter depts/courses/sections as a unit, e.g. ECON-101 (A dept and a course together). Also, I've pasted a greatly simplified query which leaves out the way I currently sort and group.
However my question deals with how I can sort the results. I want entries matching the Class_Code to be returned at the the top, followed by Course_Code, followed by Dept, then followed by Course_Title, lastly by prof. In other words, I want the results sorted by the amount of specfificity the user provides in the autocomplete. If they know the Class_Code, I'd therefore like it to be at the top.
I can't think of a way of doing this sort which doesn't require a huge query. So far the only way I can think of doing it is aliasing a bunch of LIKE comparison for each term to each field, and then ORDERing by those aliases. That's equivelant to 5 times the number of words the user enters in the autocomplete.. In other words, a huge ugly query.
Is there a simple, efficient way to do this sort? If there was something like an INSTR() function which took multiple strings to search for, I could easily just compare all the words in the autocomplete to each field, and always sort on the 5 aliases produced by that.
Any input welcome, even if it's a general suggestion that goes beyond the scope of the question. However, in advance I want to note that I'm not open to using something like FULLTEXT or a search system like Sphinx here because I don't feel its fit for a non-intensive, fast query like this one. Also, I'm not open to restructuring my database. So I'd like to do this with a good MySQL query on what I already have.
Thanks in advance..
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您是否考虑过使用 UNION 运算符?您可以将不同的查询分离到它们自己的 SELECT 语句中,然后使用 UNION 将它们连接在一起。这将自动将它们保留在您想要的组中 - 这就是您运行 SELECT 语句的顺序。
它可能会使您的查询更大,但应该是有效的。
Have you considered using the UNION operator? You could separate the different queries into their own SELECT statement, and then join them all together by using UNION. This will automatically keep them in the groups that you want them - that being the order in which you run the SELECT statements.
It may make your query bigger but should be effective.
ORDER BY 接受多个值,因此只需按照您想要的顺序列出列即可:
您可以尝试的另一种可能性是编写 SQL 生成器函数。有时,如果脚本非常丑陋并且必然会发生变化,那么使用函数以模块化格式生成脚本可以更容易地了解发生了什么。
ORDER BY accepts multiple values, so just list the columns in the order you want:
Another possibility you can try is to write an SQL generator function. Sometimes if the script is very ugly and is bound to change, having a function generate the script in modular format can make it easier to see what is going on.
你可以
这样做,代码中的所有匹配项都会在部门等的匹配项之前排序。
更新评论
如果我正确理解最后一条评论,您担心的是您将在查询中重复复杂的表达式?在这种情况下,您可以将替换/连接等包装在派生表中(见下文),或者您可以创建一个视图。
只需确保对实际列而不是计算列进行实际搜索,以确保 mysql 可以使用索引。
顺便说一句,mysql 并不关心查询是否又长又复杂,只要过滤器和连接看起来“简单”即可。
you could do
That way, all matches in code will sort before matches in dept, etc.
Updated for comment
If I understand the last comment correctly, your concerns are that you will be repeating complicated expressions in the query? In that case you could either wrap the replace/concat etc in a derived table (see below) or you can create a view.
Just be sure to do the actual search on the real columns rather then the computed columns to make sure mysql can use the indexes.
By the way, mysql doesn't care if the query is long and complicated as long as the filters and joins look "simple".