0

我有以下数据库表和一个表示该数据的视图。这些表格是分层的(如果你是这样描述的):-

编辑:我已经用 FAKE 表名称/数据(对于这篇文章)替换了我的 3 个表,因为我在 NDA 下不发布任何关于项目等的内容。所以是的.. 我并没有真正保存这样的人名:)

名字

FirstNameId INT PK NOT NULL IDENTITY
Name VARCHAR(100)

中间名

MiddleNameId INT PK NOT NULL IDENTITY
Name VARCHAR(100) NOT NULL
FirstNameId INT FK NOT NULL

姓氏

SurnameId INT PK NOT NULL IDENTITY
Name VARCHAR(100) NOT NULL
FirstNameId INT FK NOT NULL

因此,名字是父表,其他两个表是子表。

景色看起来...

人名

FirstNameId
FirstName
MiddleNameId
MiddleName
SurnameId
Surname

这是一些示例数据。

FNID FN   MNID    MN     SNID  SN
-----------------------------------
  1  Joe    1   BlahBlah   1  Blogs
  2  Jane   -    -         1  Blogs
  3  Jon    -    -         2  Skeet

现在问题来了。如何有效地搜索视图上的名称?我本来打算有一个全文搜索/目录,但我不能把它放在一个视图上(或者至少我不能让它使用 GUI 对一个视图工作)。

编辑#2:以下是一些示例搜索查询:-

exec uspSearchForPeople 'joe blogs'  (1 result)
exec uspSearchForPeople 'joe'        (1 result)
exec uspSearchForPeople 'blogs'      (2 results)
exec uspSearchForPeople 'jon skeet'  (1 result)
exec uspSearchForPeople 'skeet'      (1 result)

我应该用全名生成一个新表吗?那看起来怎么样?

请帮忙!

4

4 回答 4

0

I would have just one table with a name type column (first, middle, last) and an FK onto itself with the clustered index on the name column.

   CREATE TABLE [Name] (
        NameID INT NOT NULL IDENTITY,
        [Name] varchar(100) not null,
        NameType varchar(1) not null,
        FirstNameID int null,
    )

    ALTER TABLE [Name] ADD CONSTRAINT PK_Name  PRIMARY KEY NONCLUSTERED (NameID)
    ALTER TABLE [Name] ADD CONSTRAINT FK_Name_FirstNameID FOREIGN KEY (FirstNameID) REFERENCES [Name](NameID)
    CREATE CLUSTERED INDEX IC_Name ON [Name] ([Name], NameType)

    DECLARE @fid int
    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Joe', 'F', NULL)
    SELECT @fid = scope_identity()
    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('BlahBlah', 'M', @fid)
    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Blogs', 'L', @fid)

    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Jane', 'F', NULL)
    SELECT @fid = scope_identity()
    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Blogs', 'L', @fid)

    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Jon', 'F', NULL)
    SELECT @fid = scope_identity()
    INSERT [Name] ([Name], NameType, FirstNameID) VALUES ('Skeet', 'L', @fid)

You could then build a dynamic but paramterized WHERE clause based on the number of values to search (or hard-code them for that matter assuming there are only at most 3) using sp_executsql in a stored proc, linq to sql, or even ugly string manipulation in code.

于 2009-05-28T01:55:16.607 回答
0

我认为你想要的是一个索引表。这些表中有多少表和列并不重要,因为将内容插入到它被索引的数据库中。前任。

我会为你的名字推荐一张桌子。

NameTable
----------
Id
FirstName
MiddleName
LastName

您可以拥有任意数量的普通表...

IndexTable
----------
Id
Text 

您可以使用文本作为主键,但我总是有一个单独的 id 列作为主键(只是习惯)。

IndexItemTable
----------
Id
IndexId // Has a foreign key reference to IndexTable Id
ReferenceId // The record Id of where the text occures
ReferenceTable // The table where the  text occures

然后,当您插入名称“Jim Barbarovic Fleming”时,您还将扫描您的索引并发现它为空并为 Jim、Barbarovich 和 Fleming 创建 3 个新记录,它们都将具有相同的 referenceId,并且 ReferenceTable 将是“NameTable”然后您插入另一条记录,例如“Jim Bradley Fleming”,您将扫描索引表并看到您已经拥有“Jim”和“Fleming”的值,因此您只需创建 IndexItem 的 referenceId 为 2,ReferenceTable 为“NameTable”。

通过构建和索引,您可以通过单个文本框搜索并查找数据库中具有这些值的所有记录/字段。

注意:当您将索引插入到大写或小写然后使用 equals(value, OrdinalIgnoreCase) 时,您会想要更改所有内容。

编辑: 我不能只上传图片。我想我必须将它托管在某个地方,但它与我上面放置的表格图没有任何不同。IndexTable 的唯一关系是与 IndexItemTable。我会在代码中完成其余的工作。前任。

在名称表中插入或更新新记录期间,您必须:

  1. 扫描 IndexTable 并查看 NameTable 中的每个字段是否存在。

  2. 如果他们不这样做,您将在索引表中添加一条新记录,其中包含未找到的文本。如果他们这样做,请继续执行第 3 步。

  3. 在 IndexItemTable 中添加一条记录,带有 referenceId(NameTable 中记录的 id)和 ReferenceTable(NameTable),然后是在 IndexTable 中找到的文本的 IndexId。

然后,当他们通过您的单个文本框进行搜索时,您搜索索引表中的每个单词并从 NameTable 中返回在 IndexTable 中引用的名称。

于 2009-11-19T17:19:12.203 回答
0

疯狂的设计,可能是假表名让它变得比实际更奇怪。

根据选择使用情况创建索引。

如果您正在搜索像“Joe”这样的实际名字,您需要在 FirstNames.Name 上建立索引

如果您正在搜索像 123 这样的名字 id,您有一个索引:FirstNames.FirstNameId

如果您想在 FirstNames.name 和/或 MiddleNames.name 和/或 Surnames.name 上进行搜索,您需要对您将使用的组合进行索引,并且您所做的越多,查询就越难选择最佳组合.

放弃视图并为此目的编写专用查询:

追求第一/中间

select
  FirstNames.name
    ,MiddleNames.name
    ,Surnames.name
  FROM FirstNames
    INNER JOIN MiddleNames ON FirstNames.FirstNameId=MiddleNames.FirstNameId 
    INNER JOIN Surnames ON FirstNames.FirstNameId=Surnames.FirstNameId 
  WHERE FirstNames.Name='John'
    AND MiddleNames.Name='Q'

最后一个

select
  FirstNames.name
    ,MiddleNames.name
    ,Surnames.name
  FROM Surnames 
    INNER JOIN FirstNames ON Surnames.FirstNameId =FirstNames.FirstNameId
    INNER JOIN MiddleNames ON FirstNames.FirstNameId=MiddleNames.FirstNameId 
  WHERE Surnames.Name='Public'

只需确保您有索引来覆盖“where”子句中的主表

使用 SET SHOWPLAN_ALL ON 确保您使用的是索引(“扫描”是不好的“搜索”是好的“)

如果可能,编辑
在搜索之前将名称分开:

exec uspSearchForPeople 'joe',null,'blogs'  (1 result)
exec uspSearchForPeople 'joe',null,null     (1 result)
exec uspSearchForPeople  null,null,'blogs'  (2 results)
exec uspSearchForPeople 'jon',null,'skeet'  (1 result)
exec uspSearchForPeople null,null,'skeet'   (1 result)

在存储过程中,有三个查询:

if @GivenFirstName is not null 
    --search from FirstNames where FirstNames.name=@value & join in other tables
else if @GivenMiddleName is not null 
    --search from MiddleNames where MiddleNames.name=@value & join in other tables
else if @GivenLastName is not null 
    --search from Surnames where Surnames.name=@value & join in other tables
else --error no names given

在名称的所有三个表上都有一个索引。

如果您不能将名称分开,我认为您不走运,您将不得不对每个表中的每一行进行表扫描。

如果您不使用索引并且正在寻找名称,请考虑电话簿,您将需要阅读整本书

于 2009-05-28T01:17:40.863 回答
0

这似乎不是最合乎逻辑的设计决策。你为什么设计成这样?

您目前的索引结构是什么?3个表中每一个上的名称索引应该加快查询速度吗?

或者,进一步规范化并创建一个 Name 表并在三个表中的每一个中都有 NameID,然后索引 Name 表也应该会提高性能,但我认为索引 3 个表上的 name 字段会更容易并且也可以工作。

更新与选择的统计数据是什么,因为添加这些索引可能会导致性能下降。

于 2009-05-28T00:25:48.173 回答