-1

如果我在表格上有两个全文索引,例如ContactsCompanies,我该如何编写一个查询来确保搜索短语的所有单词都存在于这两个索引的之内?如何搜索多个全文索引的ANY列中的所有单词?

例如,如果我正在搜索联系人全部关键字存在于联系人记录或公司中,我该如何编写查询?

我试着在接触和公司的表都做CONTAINSTABLE,然后加入表一起,但如果我通过搜索短语中的每一个作为'"searchTerm1*' AND '"searchTerm2*"'那么只有当所有搜索词都在匹配索引和返回的记录太少。如果我通过它像'"searchTerm1*' OR '"searchTerm2*"'那么它匹配(而不是所有任何的搜索词在哪里的指标要么返回太多记录。

我也尝试创建一个索引视图,将联系人连接到公司,这样我就可以在一个镜头中搜索所有列,但不幸的是,联系人可能属于多个公司,因此我将使用的ContactKey该视图的关键不再是唯一的,因此无法创建。

看起来好像我可能需要分开单词并单独查询每个单词,然后将结果加回到一起以确保所有单词都匹配,但我无法想象我如何“ d写入该查询。

这里的模型可以是什么样子的例子:

Contact   CompanyContact Company 
-------------- -------------- ------------ 
ContactKey  ContactKey  CompanyKey 
FirstName   CompanyKey  CompanyName 
LastName 

我有名字,姓氏全文索引和其他的公司名称。

+0

你能分享有关模型的一些信息?到目前为止,我的理解是,您有两个表格:联系人和公司,并且每个表都包含ContactKey。我猜测,ContactKey不是您正在搜索的值。 – Paurian

+0

@Paurian,请参阅我的更新,并告诉我您是否需要更多信息。谢谢。 – adam0101

+0

@BogdanSahlean引发错误,指出CompanyContact不能成为CONTAINSTABLE查询的一部分,因为它不是全文索引的,而且我也无法向它添加全文索引,因为该表中没有文本。 – adam0101

回答

0

我创建了一个与任意数量的全文索引和工作的方法列。使用这种方法,可以很容易地添加额外的方面进行搜索。

  1. 斯普利特搜索短语到行的临时表
  2. 加入到该临时表来搜索上的每个应用的全文索引使用CONTAINSTABLE每个搜索词。
  3. 将结果联合在一起,并获得找到的搜索项的不同数量。
  4. 过滤掉指定的搜索词数与所找到的搜索词数不匹配的结果。

例子:

DECLARE @SearchPhrase nvarchar(255) = 'John Doe' 
DECLARE @Matches Table(
    MentionedKey int, 
    CoreType char(1), 
    Label nvarchar(1000), 
    Ranking int 
) 

-- Split the search phrase into separate words. 
DECLARE @SearchTerms TABLE (Term NVARCHAR(100), Position INT) 
INSERT INTO @SearchTerms (Term, Position) 
SELECT dbo.ScrubSearchTerm(Term)-- Removes invalid characters and convert the words into search tokens for Full Text searching such as '"word*"'. 
FROM dbo.SplitSearchTerms(@SearchPhrase) 

-- Count the search words. 
DECLARE @numSearchTerms int = (SELECT COUNT(*) FROM @SearchTerms) 

-- Find the matching contacts. 
;WITH MatchingContacts AS 
(
    SELECT 
     [ContactKey] = sc.[KEY], 
     [Ranking] = sc.[RANK], 
     [Term] = st.Term 
    FROM @SearchTerms st 
    CROSS APPLY dbo.SearchContacts(st.Term) sc -- I wrap my CONTAINSTABLE query in a Sql Function for convenience 
) 
-- Find the matching companies 
,MatchingContactCompanies AS 
(
    SELECT 
     c.ContactKey, 
     Ranking = sc.[RANK], 
     st.Term 
    FROM @SearchTerms st 
    CROSS APPLY dbo.SearchCompanies(st.Term) sc 
    JOIN dbo.CompanyContact cc ON sc.CompanyKey = cc.CompanyKey 
    JOIN dbo.Contact c ON c.ContactKey = cc.ContactKey 
) 
-- Find the matches where ALL search words were found. 
,ContactsWithAllTerms AS 
(
    SELECT 
     c.ContactKey, 
     Ranking = SUM(x.Ranking) 
    FROM (
     SELECT ContactKey, Ranking, Term FROM MatchingContacts UNION ALL 
     SELECT ContactKey, Ranking, Term FROM MatchingContactCompanies 
    ) x 
    GROUP BY c.ContactKey 
    HAVING COUNT(DISTINCT x.Term) = @numSearchTerms 
) 
SELECT 
    * 
FROM ContactsWithAllTerms c 
0

此答案已重建,以解决您的问题,使得多个字符串必须跨字段存在。请注意,在CompanyContactLink链接表中的单个键:

CREATE FULLTEXT CATALOG CompanyContact WITH ACCENT_SENSITIVITY = OFF 
GO 

CREATE TABLE Contact (ContactKey INT IDENTITY, FirstName VARCHAR(20) NOT NULL, LastName VARCHAR(20) NOT NULL) 
ALTER TABLE Contact ADD CONSTRAINT PK_Contact PRIMARY KEY NONCLUSTERED (ContactKey) 

CREATE TABLE Company (CompanyKey INT IDENTITY, CompanyName VARCHAR(50) NOT NULL) 
ALTER TABLE Company ADD CONSTRAINT PK_Company PRIMARY KEY NONCLUSTERED (CompanyKey) 
GO 

CREATE TABLE CompanyContactLink (CompanyContactKey INT IDENTITY NOT NULL, CompanyKey INT NOT NULL, ContactKey INT NOT NULL) 
GO 

INSERT INTO Contact (FirstName, LastName) VALUES ('Dipper', 'Pines') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Mabel', 'Pines') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Stanley', 'Pines') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Soos', 'Ramirez') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Wendy', 'Corduroy') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Sheriff', 'Blubs') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Bill', 'Cipher') 
INSERT INTO Contact (FirstName, LastName) VALUES ('Pine Dip', 'Nobody') 
INSERT INTO Contact (FirstNAme, LastName) VALUES ('Nobody', 'Pine Dip') 

INSERT INTO Company (CompanyName) VALUES ('Mystery Shack') 
INSERT INTO Company (CompanyName) VALUES ('Greesy Diner') 
INSERT INTO Company (CompanyName) VALUES ('Watertower') 
INSERT INTO Company (CompanyName) VALUES ('Manotaur Cave') 
INSERT INTO Company (CompanyName) VALUES ('Big Dipper Watering Hole') 
INSERT INTO Company (CompanyName) VALUES ('Lost Pines Dipping Pool') 
GO 

INSERT INTO CompanyContactLink Values (3, 5), (1, 1), (1, 2), (1, 3), (1, 4), (1,5), (5,1), (3,1), (4,1) 
GO 

CREATE FULLTEXT INDEX ON Contact (LastName, FirstName) 
KEY INDEX PK_Contact 
ON CompanyContact 
WITH STOPLIST = SYSTEM 

CREATE FULLTEXT INDEX ON Company (CompanyName) 
KEY INDEX PK_Company 
ON CompanyContact 
WITH STOPLIST = SYSTEM 
GO 

CREATE VIEW CompanyContactView 
WITH SCHEMABINDING 
AS 
    SELECT 
    CompanyContactKey, 
    CompanyName, 
    FirstName, 
    LastName 
    FROM 
    dbo.CompanyContactLink 
    INNER JOIN dbo.Company ON Company.CompanyKey = CompanyContactLink.CompanyKey 
    INNER JOIN dbo.Contact ON Contact.ContactKey = CompanyContactLink.ContactKey 
GO 

CREATE UNIQUE CLUSTERED INDEX idx_CompanyContactView ON CompanyContactView (CompanyContactKey); 
GO 

CREATE FULLTEXT INDEX ON CompanyContactView (CompanyName, LastName, FirstName) 
KEY INDEX idx_CompanyContactView 
ON CompanyContact 
WITH STOPLIST = SYSTEM 
GO 

-- Wait a few moments for the FULLTEXT INDEXing to take place. 
-- Check to see how the index is doing ... repeat the following line until you get a zero back. 

DECLARE @ReadyStatus INT 
SET @ReadyStatus = 1 
WHILE (@ReadyStatus != 0) 
BEGIN 
    SELECT @ReadyStatus = FULLTEXTCATALOGPROPERTY('CompanyContact', 'PopulateStatus') 
END 

SELECT 
    CompanyContactView.* 
FROM 
    CompanyContactView 
WHERE 
    FREETEXT((FirstName,LastName,CompanyName), 'Dipper') AND 
    FREETEXT((FirstName,LastName,CompanyName), 'Shack') 
GO 

并为你的榜样,为了与温迪在沃特陶:

SELECT 
    CompanyContactView.* 
FROM 
    CompanyContactView 
WHERE 
    FREETEXT((FirstName,LastName,CompanyName), 'Wendy') AND 
    FREETEXT((FirstName,LastName,CompanyName), 'Watertower') 
GO 
+0

这只会搜索联系人或公司。使用你的数据,如果我正在寻找联系人,Wendy是Watertower的联系人,如果我搜索“Wendy Watertower”,我希望找回Wendy的联系人密钥,但是你没有在联系人和公司之间定义任何关系。 – adam0101

+0

答案已被重建以解决您的问题;具体而言,如何在多个字段中包含多个必需的搜索字符串。 – Paurian

+0

并对其到期的地点给予一定的评价。恰巧,在彻底改变了答案之后,我开始意识到这些变化完全符合波格丹萨莱恩的建议。如果你发现这个完整的代码解决方案是对你的问题有用的东西,请确保他的评论也是upvote。 – Paurian

相关问题