我正在使用SQL搜索功能再次努力。
基本上我想要一个存储过程,它将一个字符串拆分成单词,然后对于我想要使用全文搜索检查的每个单词,如果它在2个表中的任何一个中。
如果在这些表中找到了结果,它应该将它们添加到它为其他单词找到的任何结果中,并返回一个集合,其中记录在这两个集合中。
所以这是我的算法
if null return all restaurants
declare results = empty
for each word
if in restaurant.name or cuisine.name
addRowsToResults
else if in restaurant.city
addRowsToResults
else if in restaurant.postcode
addRowsToResults
addRowsToResults
results = (results + new results) where a match is in both
我不知道从哪里开始,我已经搜索谷歌多年,但作为SQL的初学者我可能会遗漏一些条款。
这也是做这种事情的最佳方法吗?
感谢任何帮助。
修改 只是为了提供更多信息。 City,Postcode和Name都是Restaurants表中的nvarchar字段。菜肴名称位于不同的餐桌中,并通过另一张桌子与餐厅相连,因为餐厅可以提供多种菜肴。
所有这些字段都有全文搜索索引。
答案 0 :(得分:1)
这不是SQL的工作方式。你可以获得一些相同的功能,但它看起来不像你要问的那样;你正在以更加程序化的方式写作(自然而然)。
一方面,“添加结果”试图将(可能)不同的东西整合到一个集合中。你是 - 我认为 - 要求餐馆和美食,城市和邮政编码都进入同一个集合,而SQL(粗略地说)的唯一一种集合是表格,在表格中,所有行都有相同的类型。
但也许餐馆和美食,城市和邮政编码都是同一张桌子的所有字段?那么,对于给定的单词,你可以说
SELECT *
FROM your_table
WHERE restaurant like "%" + word + "%"
OR cuisine like "%" + word + "%"
OR city like "%" + word + "%"
OR postcode like "%" + word + "%";
当你想要匹配多个单词时,它开始变得复杂;这个答案是作为一个起点;也许一旦你对SQL更熟悉,你可以提出更容易回答的问题。祝你好运!
根据您的表格描述更新
SELECT r.*
FROM restaurant r
INNER JOIN link k ON k.restaurant_id = r.restaurant_id
INNER JOIN cuisine c on c.cuisine_id = k.cuisine_id
WHERE r.restaurant like "%" + word + "%"
OR c.name like "%" + word + "%"
OR r.city like "%" + word + "%"
OR r.postcode like "%" + word + "%";
不要担心哪些记录“先”回来。您的数据库速度足够快,不应该成为一个问题。
答案 1 :(得分:1)
分词function here。返回可以加入的表格。
您还应该调查metaphone或soundex,但为了支持您需要在单独的表格中预先索引您的数据,或者在单独的字段中预先计算每个单词的美式互联网或soundex代码,并对其进行索引。
答案 2 :(得分:1)
看起来您试图采用基于集合的声明性查询语言的过程方法。
首先,您可以使用表值用户定义函数将字符串拆分为结果集。像下面这样的东西会做 -
CREATE function [dbo].[csl_to_table] ( @list nvarchar(MAX) )
RETURNS @list_table TABLE ([id] nvarchar(20)) -- set this to your maximum size string
AS
BEGIN
DECLARE @index INT,
@start_index INT,
@id nvarchar(20) -- set this to your maximum size string
SELECT @index = 1
SELECT @start_index = 1
WHILE @index <= DATALENGTH(@list)
BEGIN
IF SUBSTRING(@list,@index,1) = ','
BEGIN
SELECT @id = SUBSTRING(@list, @start_index, @index - @start_index)
INSERT @list_table ([id]) VALUES (@id)
SELECT @start_index = @index + 1
END
SELECT @index = @index + 1
END
SELECT @id = SUBSTRING(@list, @start_index, @index - @start_index )
INSERT @list_table ([id]) VALUES (@id)
RETURN
END
然后使用结果集,您可以加入要查询匹配的表,并返回匹配的结果集。
答案 3 :(得分:1)
这是一个split函数,它有一个分隔符的可选参数......
CREATE FUNCTION [dbo].[fnSplit]( @List VARCHAR(4000), @Delimiter CHAR(1) = ',' )
RETURNS @Result TABLE (item VARCHAR(100))
BEGIN
DECLARE @Item VARCHAR(100)
WHILE CHARINDEX(@Delimiter,@List,0) <> 0
BEGIN
SELECT @Item = SUBSTRING(@List,1,CHARINDEX(@Delimiter,@List,0)-1)
, @List = SUBSTRING(@List,CHARINDEX(@Delimiter,@List,0)+1,LEN(@List))
IF LEN(@Item) > 0
INSERT INTO @Result
SELECT @Item
END
IF LEN(@List) > 0
INSERT INTO @Result
SELECT @List
RETURN
END
GO
然后你的查询看起来像这样...
SELECT DISTINCT
'restaurants' AS [source]
, r.ID AS [ID] --Assuming ID is your primary key column
, r.name + '(' + r.city + ', ' + r.state + ')' AS [Description]
FROM restaurants AS [r]
JOIN [dbo].[fnSplit](@Query,' ') AS [terms]
ON
ISNULL(r.name,'')
+','+ISNULL(r.city,'')
+','+ISNULL(r.postcode,'') LIKE '%'+terms.item+'%'
UNION SELECT DISTINCT
'cuisine' AS [source]
, r.ID AS [ID] --Assuming ID is your primary key column
, r.name AS [Description]
FROM cuisine AS [r]
JOIN [dbo].[fnSplit](@Query,' ') AS [terms]
ON
ISNULL(r.name,'') LIKE '%'+terms.item+'%'
fnSplit 函数将查询字词分解为表变量中的行并返回它。然后,select查询将与结果表连接。查询是不同的,因此无论查询中匹配的项数是多少,都只返回一行的实例。连接条件很容易被分解为一系列AND / OR条件,但我认为LIKE操作比连接更昂贵所以我只是连接列。
<强>更新强>
由于启用了全文索引,因此可以使用以下简化查询。
DECLARE @Phrase VARCHAR(4000)
SELECT @Phrase = item + '" OR "' FROM [dbo].[fnSplit](@Query,' ')
SET @Phrase = SUBSTRING(@Phrase,0,LEN(@Phrase)-6)
SELECT DISTINCT
'restaurants' AS [source]
, r.ID AS [ID] --Assuming ID is your primary key column
, r.name + '(' + r.city + ', ' + r.state + ')' AS [Description]
FROM restaurants AS [r]
WHERE
CONTAINS(r.name,@Phrase)
OR CONTAINS(r.city,@Phrase)
OR CONTAINS(r.postcode,@Phrase)
UNION SELECT DISTINCT
'cuisine' AS [source]
, r.ID AS [ID] --Assuming ID is your primary key column
, r.name AS [Description]
FROM cuisine AS [r]
WHERE CONTAINS(r.name,@Phrase)
答案 4 :(得分:0)
即使我想,我也无法就此发表完整的故事 - 您尚未公布表格定义或任何样本数据。
那就是说,我会做一些猜测。首先,我认为您需要以基于集合的方式使用SQL。不要考虑逐行处理 - 处理集合。然后将这些组合在一起。
答案 5 :(得分:0)
如果您在SQL中寻找For Each循环,则大多数SQL方言都有游标,允许您使用某些查询选择所有记录,然后使用Cursor迭代记录。
答案 6 :(得分:0)
要使用全文搜索,您需要使用CONTAINS关键字。查看如何在网上书籍中使用它(我必须参加会议或者我会提供一个例子)。