T-SQL根据BIT参数值查找匹配的行

时间:2015-05-11 21:21:55

标签: sql sql-server database stored-procedures

我正在尝试创建一个存储过程,该存储过程返回person表中具有特定列相同值的行。我希望存储过程接受@match_on_forenames BIT@match_on_surname BIT等参数值。因此,例如EXEC find_matching @match_on_forenames 1, @match_on_surname 1会在表中找到名称和姓氏字段匹配的行,显然不匹配自身。

我的存储过程类似于:

ALTER PROC get_matching_records
    @match_on_forenames BIT,
    @match_on_surname BIT
AS
SELECT DISTINCT
    p.forenames, p.surname
FROM 
    person p
WHERE       
    EXISTS 
      (
            SELECT 
                p1.forenames, p1.surname
            FROM 
                person p1                                                                   
            WHERE                                                                                                                            
                (((@match_on_forenames = 1 AND p.forenames = p1.forenames AND p.id <> p1.id)) OR @match_on_forenames = 0)
                AND (((@match_on_surname = 1 AND p.surname = p1.surname AND p.id <> p1.id)) OR @match_on_surname = 0)
                )

当我介绍OR @match_on_forenames时,查询的性能变得非常差。

我最好如何处理这个问题?

非常感谢。

2 个答案:

答案 0 :(得分:0)

这是你的逻辑:

WHERE EXISTS (SELECT 1
              FROM person p1                                                                   
              WHERE                                                                                                                            
                (((@match_on_forenames = 1 AND p.forenames = p1.forenames AND p.id <> p1.id)) OR @match_on_forenames = 0)
                AND (((@match_on_surname = 1 AND p.surname = p1.surname AND p.id <> p1.id)) OR @match_on_surname = 0)
             )

如果在没有or的情况下很快,那么有三个条件可以解决问题:

WHERE (@match_on_forenames = 1 and @match_on_surname = 1 and
       EXISTS (SELECT 1
               FROM person p1                                                                   
               WHERE (p.forenames = p1.forenames AND p.id <> p1.id) AND
                     (p.surname = p1.surname AND p.id <> p1.id)
              )
      ) OR
      (@match_on_forenames = 0 and @match_on_surname = 1 and
       EXISTS (SELECT 1
               FROM person p1                                                                   
               WHERE (p.surname = p1.surname AND p.id <> p1.id)
              )
      ) OR
      (@match_on_forenames = 1 and @match_on_surname = 0 and
       EXISTS (SELECT 1
               FROM person p1                                                                   
               WHERE (p.forenames = p1.forenames AND p.id <> p1.id) 
              )
      )

根据您对更简单查询更快的观察,每个exists子句都应该很快。

答案 1 :(得分:0)

我通常避免在我的SQL语句中使用OR 这是我要做的,在同一张桌子上使用JOIN。

SELECT DISTINCT
p.forenames, p.surname
FROM 
person p
inner join person pmatch on
    pmatch.id <> p.id
    and
    case when @match_on_forenames =1 then pmatch.forenames else p.forenames end = p.forenames
    and 
    case when @match_on_surname =1 then pmatch.surname else p.surname end = p.surname