我正在寻找一个很好的解决方案来有效地使用SQL Serve r2005的containsstable功能。目前我有,例如,员工和地址表。
-Employee
Id
Name
-Address
Id
Street
City
EmployeeId
现在,用户只能在一个文本框中输入搜索字词,我希望将这些字词拆分并使用“AND”运算符进行搜索。 FREETEXTTABLE似乎自动与“OR”一起使用。
现在让我们说用户输入“John Hamburg”。这意味着他想在汉堡找到约翰。 所以这就是“John AND Hamburg”。
因此,以下将不包含任何结果,因为CONTAINSTABLE会检查“John AND Hamburg”的每一列。
所以我的问题是:在多个列/表中使用AND运算符执行全文搜索的最佳方法是什么?
SELECT *
FROM Employee emp
INNER JOIN
CONTAINSTABLE(Employee, *, '(JOHN AND Hamburg)', 1000) AS keyTblSp
ON sp.ServiceProviderId = keyTblSp.[KEY]
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
UNION ALL
SELECT *
FROM Employee emp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
INNER JOIN
CONTAINSTABLE([Address], *, '(JOHN AND Hamburg)', 1000) AS keyTblAddr
ON addr.AddressId = keyTblAddr.[KEY]
...
答案 0 :(得分:6)
这更像是一种语法问题。你如何只用一个输入框来判断用户的意图?
在不知道用户意图的情况下,您可以期望的最好的是OR条款,并获得最高排名。
否则,您需要编写大量逻辑,具体取决于传入的字数:
2个字:
搜索术语1的员工数据,搜索术语2的员工数据,搜索术语1的地址数据,搜索术语2的搜索地址数据。按术语合并结果,按大多数命中顺序合并。
3个字:
搜索术语1的员工数据,搜索术语2的员工数据,搜索术语3的员工数据,搜索术语1的地址数据,搜索术语2的术语数据,搜索术语3的术语数据。按术语合并结果,按大多数命中排序。
等...
我想我会重新设计GUI,将输入分为名称和地址,至少。如果无法做到这一点,请对效果执行语法规则“在逗号出现之前,第一个单词将被视为名称,之后的任何单词都将被视为地址”
修改强>
你最好的选择仍然是OR条款,并采取最高排名的命中。这是一个例子,并举例说明为什么如果不对输入进行一些预处理来判断用户的意图,这是不理想的:
insert into Employee (id, [name]) values (1, 'John Hamburg')
insert into Employee (id, [name]) values (2, 'John Smith')
insert into Employee (id, [name]) values (3, 'Bob Hamburg')
insert into Employee (id, [name]) values (4, 'Bob Smith')
insert into Employee (id, [name]) values (5, 'John Doe')
insert into Address (id, street, city, employeeid) values (1, 'Main St.', 'Springville', 1)
insert into Address (id, street, city, employeeid) values (2, 'Hamburg St.', 'Springville', 2)
insert into Address (id, street, city, employeeid) values (3, 'St. John Ave.', 'Springville', 3)
insert into Address (id, street, city, employeeid) values (4, '5th Ave.', 'Hamburg', 4)
insert into Address (id, street, city, employeeid) values (5, 'Oak Lane', 'Hamburg', 5)
既然我们不知道哪些关键字适用于哪个表,我们必须假设它们可以应用于任何一个表,所以我们必须对每个表使用OR,对结果进行UNION,聚合它们,然后计算最高等级。
SELECT Id, [Name], Street, City, SUM([Rank])
FROM
(
SELECT emp.Id, [Name], Street, City, [Rank]
FROM Employee emp
JOIN [Address] addr ON emp.Id = addr.EmployeeId
JOIN CONTAINSTABLE(Employee, *, 'JOHN OR Hamburg') AS keyTblEmp ON emp.Id = keyTblEmp.[KEY]
UNION ALL
SELECT emp.Id, [Name], Street, City, [Rank]
FROM Employee emp
JOIN [Address] addr ON emp.Id = addr.EmployeeId
JOIN CONTAINSTABLE([Address], *, 'JOHN OR Hamburg') AS keyTblAdd ON addr.Id = keyTblAdd.[KEY]
) as tmp
GROUP BY Id, [Name], Street, City
ORDER BY SUM([Rank]) DESC
这不太理想,这就是你得到的例子(在你的情况下,你会希望汉堡的John Doe先出现):
Id Name Street City Rank 2 John Smith Hamburg St. Springville 112 3 Bob Hamburg St. John Ave. Springville 112 5 John Doe Oak Lane Hamburg 96 1 John Hamburg Main St. Springville 48 4 Bob Smith 5th Ave. Hamburg 48
但是,在将输入提交给SQL之前,如果没有解析输入,那么这是最好的,可以根据用户的需求进行“最佳猜测”。
答案 1 :(得分:2)
我遇到了同样的问题。这是我的解决方案,适用于我的案例:
我创建了一个返回我想要的列的视图。我添加了另一个额外的列,它聚合了我想搜索的所有列。所以,在这种情况下,视图就像
SELECT emp.*, addr.*, ISNULL(emp.Name,'') + ' ' + ISNULL(addr.City, '') AS SearchResult
FROM Employee emp
LEFT OUTER JOIN [Address] addr ON addr.EmployeeId = emp.EmployeeId
在此之后,我在SearchResult列上创建了一个全文索引。然后,我在这个专栏上搜索
SELECT *
FROM vEmpAddr ea
INNER JOIN CONTAINSTABLE(vEmpAddr, *, 'John AND Hamburg') a ON ea.ID = a.[Key]