0

我在 SQL 数据库中有两个表;'course' 和 'event',课程表有 courseID (pk)、coursecode 和 coursetitle 字段。事件表有 eventID (pk) courseID (fk)、startdate、enddate。

我需要使用事件表的开始日期返回所有课程的列表,其中有一列显示它发生的最后日期,以及它应该发生的下一个日期。

我可以在事件表中获取最近日期或特定课程的下一个日期,如下所示:

SELECT TOP 1
    startdate as nextdate    
FROM event

WHERE 
    CONVERT(VARCHAR(8),startdate,112) > CONVERT(VARCHAR(8), GETDATE(), 112)
    AND coursecode = 'acc01'

ORDER BY startdate ASC

我希望结果如下所示:

+------------+-------------+------------+-------------+------------+-------------+
| coursecode | coursetitle | lastevent  | lasteventid | nextevent  | nexteventid |
+------------+-------------+------------+-------------+------------+-------------+
| acc01      | Access      | 2012-09-30 | 20127       | 2013-12-10 | 35612       | 
| wrd37      | Word        | 2013-11-02 | 34816       | NULL       | NULL        |
+------------+-------------+------------+-------------+------------+-------------+

我需要显示每个课程代码一次(课程来自不同的供应商,因此课程代码可能不是唯一的字段,因此是 courseid 字段)。课程可能没有过去的日期、未来的日期或任何日期。Null 在这些日期/eventid 字段中很好,因为我将在报告设计中格式化它们。

我希望我没有重复一个问题,但到目前为止我还没有在这里找到任何东西。

预先感谢大家的任何帮助

4

2 回答 2

1

您可以使用OUTER APPLY实现此目的:

WITH CourseCodeEvents AS
(   SELECT  c.CourseCode, e.EventID, e.StartDate, e.EndDate
    FROM    Course c
            INNER JOIN Event e
                ON e.CourseID = c.CourseID
), DistinctCourseCode AS
(   SELECT  DISTINCT CourseCode, CourseTitle
    FROM    Course
)
SELECT  c.CourseCode,
        c.CourseTitle,
        LastEvent = LastEvent.StartDate,
        LastEventID = LastEvent.EventID,
        NextEvent = NextEvent.StartDate,
        NextEventID = NextEvent.EventID
FROM    DistinctCourseCode c
        OUTER APPLY
        (   SELECT  TOP 1 EventID, StartDate, EndDate
            FROM    CourseCodeEvents e
            WHERE   e.CourseCode = c.CourseCode
            AND     e.StartDate > CAST(GETDATE() AS DATE)
            ORDER BY StartDate ASC
        ) NextEvent
        OUTER APPLY
        (   SELECT  TOP 1 EventID, StartDate, EndDate
            FROM    CourseCodeEvents e
            WHERE   e.CourseCode = c.CourseCode
            AND     e.StartDate <= CAST(GETDATE() AS DATE)
            ORDER BY StartDate DESC
        ) LastEvent;

注意,我也改变了这个:

CONVERT(VARCHAR(8),startdate,112) > CONVERT(VARCHAR(8), GETDATE(), 112)

StartDate < CAST(GETDATE() AS DATE)

将日期转换为 varchars 然后比较它们不是删除时间元素的有效方法。投射到DATE更有效(如果你有 2008+)。对于其他版本的 sql-server 中的其他方法,请阅读本文

于 2013-11-04T11:19:49.593 回答
0

根据您使用的 sql 风格,尝试类似以下内容:

;WITH cteEventsLast
AS
(
    SELECT e.CourseID, 
           MAX(e.StartDate) AS StartDate
    FROM Event e
    WHERE e.StartDate < GETDATE()
    GROUP BY e.CourseID
),

WITH cteEventsNext
AS
(
    SELECT e.CourseID, 
           MIN(e.StartDate) AS StartDate
    FROM Event e
    WHERE e.StartDate >= GETDATE()
    GROUP BY e.CourseID
)

SELECT c.CourseCode,
       c.CourseTitle,
       el.StartDate AS LastEvent,
       en.StartDate AS NextEvent
FROM Course c LEFT OUTER JOIN
     cteEventsLast el ON (el.CourseID = c.CourseID) LEFT OUTER JOIN
     cteEventsNext en ON (en.CourseID = c.CourseID)

此示例使用公用表表达式,您可以将其用于 TSQL / MSSQL 服务器。但根据您的 SQL 风格,您可能需要使用稍微不同的 SQL

如果您不能使用 CTE,则可以将 cteEventsLast 和 cteEventsNext 作为 FROM 子句中的子查询

我也不会用

CONVERT(VARCHAR(8),startdate,112) > CONVERT(VARCHAR(8), GETDATE(), 112)

比较日期,就像您在问题中所说的那样。而是直接比较日期,即像这样

startdate > GETDATE()
于 2013-11-04T11:11:48.297 回答