SQL 返回最近日期和下一个日期的课程列表
Posted
技术标签:
【中文标题】SQL 返回最近日期和下一个日期的课程列表【英文标题】:SQL return list of courses with most recent date and next date 【发布时间】:2013-11-04 10:52:22 【问题描述】:我在一个 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 字段)。课程可能没有过去的日期、未来的日期或任何日期。在这些日期/eventid 字段中使用 Null 很好,因为我将在报告设计中对它们进行格式化。
我希望我不是在重复一个问题,但到目前为止我还没有在这里找到任何东西。
提前感谢大家的帮助
【问题讨论】:
什么是 sql 风格? @geomagas 2008 R2 SP2 多个coursecode
s 也将有多个coursetitle
s 每个coursecode
。标题选择的标准是什么?
@geomagas 不太清楚你的意思,课程标题和课程代码的组合应该是唯一的,但是表中有一个单独的 CourseID 字段,它是主键,这是用作连接的。在最终输出中,我可以将 CourseID、CourseCode 和 Coursetitle 显示为前 3 列
想象一下(coursecode,coursetitle)
组合('acc01','Access foo')
和('acc01','Access bar')
。如果查询只返回一次'acc01'
,它会选择哪个标题?
【参考方案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 中的其他方法,请阅读this article。
【讨论】:
非常感谢,虽然我还没有完全测试过,但这似乎可行。我的日期转换混乱的原因是因为我们数据库中的日期字段是整数,例如今天日期的20131104
。我对 SQL 很陌生,所以转换日期字符串可能是我的混乱尝试,所以我可以得到一个日期来比较。【参考方案2】:
根据您使用的 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()
【讨论】:
OP 专门要求每个CourseCode
只出现一次。以上是关于SQL 返回最近日期和下一个日期的课程列表的主要内容,如果未能解决你的问题,请参考以下文章