0

我有一个包含三个输入字段的搜索(为了参数,假设 LastName、Last4Ssn 和 DateOfBirth)。这三个输入字段位于动态网格中,用户可以在其中选择搜索这三个字段的一个或多个组合。例如,用户可能会根据以下表示进行搜索:

LastName    Last4Ssn    DateOfBirth
--------    --------    -----------
Smith       NULL        1/1/1970
Smithers    1234        NULL
NULL        5678        2/2/1980

在示例中,第一行表示按 LastName 和 DateOfBirth 进行的搜索。第二个,按 LastName 和 Last4Ssn。第三个是 Last4Ssn 和 DateOfBirth。这个例子有点做作,因为现实世界的场景有四个字段。至少必须用搜索数据填写两个字段(不用担心如何验证),并且可能所有字段都已填写。

在不使用游标的情况下,如何使用每行中的给定值作为过滤器使用该数据连接到现有表?目前,我有一个游标,它遍历上表的每一行,根据具有值的列执行连接,并将找到的数据插入到临时表中。像这样的东西:

CREATE TABLE #results (
    Id INT,
    LastName VARCHAR (26),
    Last4Ssn VARCHAR (4),
    DateOfBirth DATETIME
)

DECLARE @lastName VARCHAR (26)
DECLARE @last4Ssn VARCHAR (4)
DECLARE @dateOfBirth DATETIME

DECLARE search CURSOR FOR
    SELECT LastName, Last4Ssn, DateOfBirth
    FROM #searchData

OPEN search
    FETCH NEXT FROM search
    INTO @lastName, @last4Ssn, @dateOfBirth

    WHILE @@FETCH_STATUS = 0
    BEGIN           
        INSERT INTO #results
            SELECT s.Id, s.LastName, s.Last4Ssn, s.DateOfBirth
            FROM SomeTable s
            WHERE Last4Ssn = ISNULL(@last4Ssn, Last4Ssn)
                AND DateOfBirth = ISNULL(@dateOfBirth, DateOfBirth)
                AND (
                    LastName = ISNULL(@lastName, LastName)
                    OR LastName LIKE @lastName + '%'
                )
        FETCH NEXT FROM search
        INTO @lastName, @last4Ssn, @dateOfBirth
    END
CLOSE search
DEALLOCATE search

我希望有一些方法可以避免光标使代码更具可读性。性能不是问题,因为用于搜索的表中的记录永远不会超过 5-10 条,但我认为对于不止几个,一次查询所有数据而不是一个更有效一次排。我的示例中的SomeData表格可能非常大。

4

1 回答 1

1

我不明白为什么你不能把两张表连接在一起:

CREATE TABLE #results (
    Id INT,
    LastName VARCHAR (26),
    Last4Ssn VARCHAR (4),
    DateOfBirth DATETIME
)

INSERT INTO #results
select s.id, s.lastname, s.last4ssn, s.dateofbirth
from SomeTable s
join #searchData d
    ON s.last4ssn = isnull(d.last4ssn, s.last4ssn)
    AND s.dateofbirth = isnull(d.dateofbirth, s.dateofbirth)
    AND (s.lastname = isnull(d.lastname, s.lastname) OR
        OR s.lastname like d.lastname + '%')

编辑:

由于数据很大,我们需要一些好的索引。一个索引还不够好,因为您实际上有 3 个子句 OR'd 在一起。所以第一步是创建这些索引:

CREATE TABLE SomeData (
    Id INT identity(1,1),
    LastName VARCHAR (26),
    Last4Ssn VARCHAR (4),
    DateOfBirth DATETIME
)

create nonclustered index ssnlookup on somedata (last4ssn)
create nonclustered index lastnamelookup on somedata (lastname)
create nonclustered index doblookup on somedata (dateofbirth)

下一步涉及制作查询以使用这些索引。我不确定这里最好的方法是什么,但我认为将 4 个查询联合在一起:

with searchbyssn as (
  select somedata.* from somedata join #searchData 
    on somedata.last4ssn = #searchData.last4ssn
), searchbyexactlastname as (
  select somedata.* from somedata join #searchData
    on somedata.lastname = #searchData.lastname
), searchbystartlastname as (
  select somedata.* from somedata join #searchData
    on somedata.lastname like #searchdata.lastname + '%'
), searchbydob as (
  select somedata.* from somedata join #searchData 
    on somedata.dateofbirth = #searchData.dateofbirth
), s as (
  select * from searchbyssn
  union select * from searchbyexactlastname
  union select * from searchbystartlastname
  union select * from searchbydob
)
select s.id, s.lastname, s.last4ssn, s.dateofbirth
from s
join #searchData d
   ON (d.last4ssn is null or s.last4ssn = d.last4ssn)
   AND s.dateofbirth = isnull(d.dateofbirth, s.dateofbirth)
   AND (s.lastname = isnull(d.lastname, s.lastname)
       OR s.lastname like d.lastname + '%')

这是一个显示 4 个索引搜索的小提琴:http ://sqlfiddle.com/#!6/3741d/3

它显示了联合的大量资源使用情况,但我认为与大型表的索引扫描相比,这可以忽略不计。它不会让我生成超过几百行的样本数据。由于结果行数很少,最后加入 #searchData 并再次过滤所有结果并不昂贵。

于 2013-06-21T04:02:00.013 回答