在相关表中使用可选参数的SQL查询

时间:2017-06-23 15:42:21

标签: sql sql-server

我有一个与此类似的架构:

Person
----------------
Id (PK)
Name

EventRegistration
----------------
EventId (PK, FK)
PersonId (PK, FK)
DateRegistered

-- EDIT: Note that a single person can registered for multiple events.

我需要编写一个查询,搜索注册在提供的日期范围内发生的任何事件的所有人的姓名(即DateRegistered应该在DateRangeStartDateRangeEnd内) 。诀窍是,输入参数是可选的。因此,您可以定义两者,仅定义开始日期,仅定义结束日期或两者都不定义。这些将分别解释为“此范围内的所有内容”,“此日期之后/之后的所有内容”,“此日期之前/之前的所有内容”以及“所有人员,无论任何事件注册。”

所以我提出了一些有效的方法,但我想知道是否可以帮助改善这一点:

-- Assume parameters @DateRangeStart and @DateRangeEnd (both date) are provided by user input

SELECT p.Name
FROM Person p
WHERE 
    (@DateRangeStart IS NULL OR EXISTS (
        SELECT TOP 1 PersonId
        FROM EventRegistration
        WHERE PersonId = p.Id
            AND DateRegistered >= @DateRangeStart
            AND (@DateRangeEnd IS NULL OR DateRegistered <= @DateRangeEnd)
        )
    ) AND
    (@DateRangeEnd IS NULL OR EXISTS (
        SELECT TOP 1 PersonId
        FROM EventRegistration
        WHERE PersonId = p.Id
            AND (@DateRangeStart IS NULL OR DateRegistered >= @DateRangeStart)
            AND DateRegistered <= @DateRangeEnd
        )
    )

3 个答案:

答案 0 :(得分:2)

这样的事情应该有效:

SELECT DISTINCT p.Name
FROM Person p
LEFT JOIN EventRegistration e
ON p.Id = e.PersonId
WHERE (@DateRangeStart IS NULL OR DateRegistered >= @DateRangeStart)
AND (@DateRangeEnd IS NULL OR DateRegistered <= @DateRangeEnd)

答案 1 :(得分:1)

一种更加修改的,干净的方法,就是将where子句布尔为布尔值。

declare @DateRangeStart datetime,  @DateRangeEnd datetime
set @DateRangeStart = null
set @DateRangeEnd = null

select 
    Name
    ,Title
    ,DateRegistered
From
    Person p
    left join
        EventRegistration er on
        er.PersonID = p.ID
    left join
        Event e on
        e.id = er.EventID
where
    (er.DateRegistered >= @DateRangeStart or @DateRangeStart is null)
    and
    (er.DateRegistered <= @DateRangeEnd or @DateRangeEnd is null)

答案 2 :(得分:1)

由于NULL比较不利用索引,我会用有效日期替换null参数,然后使用简单连接。它应该很快。

@DateRangeStart = Coalesce(@DateRangeStart , MinDate)
@DateRangeEnd = Coalesce(@DateRangeEnd , MaxDate)

select distinct p.name
from Person p join EventRegistration e on p.personId = e.personId and
     e.DateRegistered  between @DateRangeStart  and @DateRangeEnd 

如果可以使用动态SQL,则为另一种选择:

query=  select distinct p.name
        from Person p join EventRegistration e 
                  on p.personId = e.personId

if DateRangeStart != null query += 'and DateRegistered >= @DateRangeStart '
if DateRangeEnd  != null query += 'and DateRegistered <= @DateRangeEnd  '

executeQuery(...)