我有一张包含以下内容的表格:
我希望有一个搜索功能可以搜索整个层次结构,例如,这是一个类别的面包屑:
摩托车/日本/川崎/ 600cc至800cc / 1998-2004
如果有人搜索“600cc Kawasaki”,我希望退回上述类别。所以具有最多匹配的类别路径应该返回。
此刻我想出了这个:
IF ISNULL(@searchTerm, '') = ''
SET @searchTerm = '""'
DECLARE @Result TABLE (CategoryId int)
DECLARE CategoryCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT CategoryId, ParentId, Name
FROM Category
WHERE FREETEXT([Name], @searchTerm)
OPEN CategoryCursor
DECLARE @CategoryId int
DECLARE @ParentId int
DECLARE @Name nvarchar(100)
FETCH NEXT FROM CategoryCursor INTO @CategoryId, @ParentId, @Name
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @FullPath nvarchar(1000)
SET @FullPath = @Name
WHILE @ParentId <> 0
BEGIN
SELECT @ParentId = ParentId, @Name = [Name]
FROM Category
WHERE CategoryId = @ParentId
SET @FullPath = @Name + '\' + @FullPath
END
-- Check if @FullPath contains all of the searchterms
DECLARE @found bit
DECLARE @searchWords NVARCHAR(100)
DECLARE @searchText NVARCHAR(255)
DECLARE @pos int
SET @found = 1
SET @searchWords = @searchTerm + ' '
SET @pos = CHARINDEX(' ', @searchWords)
WHILE @pos <> 0
BEGIN
SET @searchText = LEFT(@searchWords, @pos - 1)
SET @searchWords = STUFF(@searchWords, 1, @pos, '')
SET @pos = CHARINDEX(' ', @searchWords)
IF @searchText = '' CONTINUE
IF @FullPath NOT LIKE '%' + @searchText + '%'
BEGIN
SET @found = 0
BREAK
END
END
IF @found = 1
INSERT INTO @Result VALUES(@CategoryId)
FETCH NEXT FROM CategoryCursor INTO @CategoryId, @ParentId, @Name
END
CLOSE CategoryCursor
DEALLOCATE CategoryCursor
SELECT *
FROM Category
WHERE categoryID IN (SELECT categoryId FROM @Result)
这将首先找到包含任何搜索词的所有catagorynames。问题是,我不希望其他品牌的“600cc”返回,只有与“川崎”相关的那个。 接下来,我为当前类别构建面包屑,看它是否包含所有搜索词。
它有效,但我认为它是无效的,所以我正在寻找一种更好的方法。
也许将完整路径作为文本存储在新列中并搜索它?
答案 0 :(得分:0)
我建议使用2008年的hierarchyid。你基本上会设置这样的层次结构
/ 1 / - 根节点 / 1/1 / - 摩托车 / 1/1/1 / - 日本 / 1/1/1/1 / - 川崎 / 1/1/1/2 / - 本田 / 1/1 / 2 / - 美国 / 1/1/2/1 / - 哈利。
然后你可以使用hierarchyid从你的600cc 1984川崎一直到摩托车的整个树。
以下是编程Microsoft SQL Server 2008的代码示例
CREATE FUNCTION dbo.fnGetFullDisplayPath(@EntityNodeId hierarchyid) RETURNS varchar(max) AS
BEGIN
DECLARE @EntityLevelDepth smallint
DECLARE @LevelCounter smallint
DECLARE @DisplayPath varchar(max)
DECLARE @ParentEmployeeName varchar(max)
-- Start with the specified node
SELECT @EntityLevelDepth = NodeId.GetLevel(),
@DisplayPath = EmployeeName
FROM Employee
WHERE NodeId = @EntityNodeId
-- Loop through all its ancestors
SET @LevelCounter = 0
WHILE @LevelCounter < @EntityLevelDepth
BEGIN
SET @LevelCounter = @LevelCounter + 1
SELECT @ParentEmployeeName = EmployeeName
FROM Employee WHERE NodeId = (SELECT NodeId.GetAncestor(@LevelCounter)
FROM Employee
WHERE NodeId = @EntityNodeId)
-- Prepend the ancestor name to the display path
SET @DisplayPath = @ParentEmployeeName + ' > ' + @DisplayPath
END
RETURN(@DisplayPath)
END
My / 1/1/2表示是字符串表示。在数据库中,您实际上会看到十六进制表示(例如0x79)。
hierarchyid上有一些关键函数。
declare @motorcycleAncestor hieararchyid
select @motorcycleAncestor = nodeId.GetAncestor(1)
from parts
where Label = 'motorcycle'
select * from Parts
where Node.GetAncestor(1) = @motorcyleAncestor;
这个查询做了几件事。首先,它获取包含“Motorcycle”作为标签的节点的层次结构ID。 (我假设hiearchy字段被命名为'nodeid'但你显然可以称之为。)
接下来,它获取此节点值并查找摩托车的所有直接子项(谁的祖先,1级,是摩托车节点。您实际上可以指定任何值,如GetAncestor(3)将是祖先3级以上)。那么在那种情况下,它会找到日本,美国,德国等。
还有另一种方法,称为IsDescendantOf( node )。您可以像这样使用它:
declare @motorcycleAncestor hieararchyid
select @motorcycleAncestor = nodeId.GetAncestor(1)
from parts
where Label = 'motorcycle'
select * from Parts
where Node.IsDescendantOf(@motorcycleAncestor) = 1
这将返回摩托车下面的所有儿童(任何等级)。它实际上还包括摩托车。
您可以通过不同方式组合这些。例如,我们在各种组织结构图中使用它们。我们能够为单个用户或用户及其兄弟姐妹(完全相同级别的每个人)以及用户及其所有后代显示结果。
所以我可以展示您的信息,或者我可以向您所在部门的每个人展示,或者我可以向您公司的每个人展示。