查找每个客户的第二个约会日期

时间:2012-01-02 23:28:02

标签: sql sql-server aggregate common-table-expression

这是一个措辞严厉的标题,但我无法想出更好的东西,抱歉!

我们有一张有效的表格(为简洁而修剪):

create table Appointment (
    AppointmentId       int     not null identity(1, 1),
    CustomerId          int     not null,
    AppointmentDate     date    not null,

    constraint PK_Appointment primary key (AppointmentId),
    constraint FK_Appointment_Customer foreign key (CustomerId) references Customer(CustomerId)
)

我们正在尝试撰写查询,查询在指定日期范围内进行 SECOND 约会的所有客户的详细信息。请注意,客户可能在同一天有两次约会。

我们可以使用一些CTE来做到这一点,但我确定有更好的方法(可能使用某种row_number类型的函数?)。有什么建议?我真的不喜欢我们的解决方案是它完全不灵活(当他们想要在给定的日期范围内看到第三次约会时会发生什么等)。

反正;这就是我们想出的:

declare @startDate date = '2011-12-01'
declare @endDate date = '2011-12-31'
;
-- Limit to appointments before the end date
with AppointmentDates as (
    select
        AppointmentId,
        CustomerId,
        AppointmentDate
    from
        Appointment
    where
        AppointmentDate < @endDate
),

-- Get first appointment date - careful to cater for customers who have had
-- two appointments on the same day
FirstAppointments as (
    select
        CustomerId,
        Min(AppointmentId) AppointmentId,
        Min(AppointmentDate) AppointmentDate
    from
        AppointmentDates
    group by
        CustomerId
),

-- Second appointment date
SecondAppointments as (
    select
        AppointmentDates.CustomerId,
        Min(AppointmentDates.AppointmentId) AppointmentId,
        Min(AppointmentDates.AppointmentDate) AppointmentDate
    from
        AppointmentDates
        inner join FirstAppointments on AppointmentDates.CustomerId = FirstAppointments.CustomerId
    where
        AppointmentDates.AppointmentId > FirstAppointments.AppointmentId
    group by 
        AppointmentDates.CustomerId
    having
        Min(AppointmentDates.AppointmentDate) > @startDate
)

-- Bulk of query goes here; trimmed for brevity
select * from SecondAppointments

2 个答案:

答案 0 :(得分:2)

是的,使用ROW_NUMBER()您可以更轻松地解决此问题:

;WITH ranked AS (
  SELECT
    CustomerId,
    AppointmentId,
    AppointmentDate,
    VisitNumber = ROW_NUMBER() OVER (PARTITION BY CustomerId
                                         ORDER BY AppointmentDate)
  FROM AppointmentDates
)
SELECT
  CustomerId,
  AppointmentId,
  AppointmentDate
FROM ranked
WHERE VisitNumber     =  @visitNumber
  AND AppointmentDate >= @startDate
  AND AppointmentDate <  @endDate

答案 1 :(得分:0)

应该使用TOP的嵌套用法。请注意,内循环上的排序顺序是降序。这样外部循环以降序获得第一个条目。这应该适用于找到任何第n个位置。

SELECT TOP 1 * 
FROM (
    SELECT TOP 2 * 
    FROM employee
    GROUP BY CustomerID
    ORDER BY AppointmentDate ASC) a
GROUP BY CustomerID
ORDER BY AppointmentDate DESC

请注意,我没有测试过这个SQL。

修正以反映第二个appt,而不是第二个最新的appt。

希望这有帮助。