我正在尝试编写一个SQL(服务器)查询,该查询将返回当天的所有事件,对于列recurring
= 1的所有事件,我希望它在当天返回此事件在活动结束后的52周内举行。
我的表格结构如下:
Event
{
event_id (PK)
title,
description,
event_start DATETIME,
event_end DATETIME,
group_id,
recurring
}
Users
{
UserID (PK)
Username
}
Groups
{
GroupID (PK)
GroupName
}
Membership
{
UserID (FK)
GroupID (FK)
}
我到目前为止的代码如下:
var db = Database.Open("mPlan");
string username = HttpContext.Current.Request.Cookies.Get("mpUsername").Value;
var listOfGroups = db.Query("SELECT GroupID FROM Membership WHERE UserID = (SELECT UserID from Users WHERE Username = @0 )", username);
foreach(var groupID in listOfGroups)
{
int newGroupID = groupID.GroupID;
var result = db.Query(
@"SELECT e.event_id, e.title, e.description, e.event_start, e.event_end, e.group_id, e.recurring
FROM event e
JOIN Membership m ON m.GroupID = e.group_id
WHERE e.recurring = 0
AND m.GroupID = @0
AND e.event_start >= @1
AND e.event_end <= @2
UNION ALL
SELECT e.event_id, e.title, e.description, DATEADD(week, w.weeks, e.event_start), DATEADD(week, w.weeks, e.event_end), e.group_id, e.recurring
FROM event e
JOIN Membership m ON m.GroupID = e.group_id
CROSS JOIN
( SELECT row_number() OVER (ORDER BY Object_ID) AS weeks
FROM SYS.OBJECTS
) AS w
WHERE e.recurring = 1
AND m.GroupID = @3
AND DATEADD(WEEK, w.Weeks, e.event_start) >= @4
AND DATEADD(WEEK, w.Weeks, e.event_end) <= @5", newGroupID, start, end, newGroupID, start, end
);
这导致当一个查询存储在数据库中的事件的日期时,返回此事件和52周的事件。当在这一周之后的一周查询事件时,不会返回任何内容。
答案 0 :(得分:1)
我会针对一些简单的SQL一次检查一个参数,只是为了将它们排除在可能的罪魁祸首之外。像这样:
var result = db.Query("select r=cast(@0 as varchar(80))",username);
var result = db.Query("select r=cast(@0 as int)",newGroupID);
var result = db.Query("select r=cast(@0 as datetime)",start);
var result = db.Query("select r=cast(@0 as datetime)",end);
答案 1 :(得分:1)
最简单的解决方案是改变以下两行
AND e.event_start >= @4
AND e.event_end <= @5"
到
AND DATEADD(WEEK, w.Weeks, e.event_start) >= @4
AND DATEADD(WEEK, w.Weeks, e.event_end) <= @5"
但是,我建议将所有这些SQL放入存储过程中,SQL-Server将缓存执行计划,这将导致(略微)更好的性能。
CREATE PROCEDURE dbo.GetEvents @UserName VARCHAR(50), @StartDate DATETIME, @EndDate DATETIME
AS
BEGIN
-- DEFINE A CTE TO GET ALL GROUPS ASSOCIATED WITH THE CURRENT USER
;WITH Groups AS
( SELECT GroupID
FROM Membership m
INNER JOIN Users u
ON m.UserID = u.UserID
WHERE Username = @UserName
GROUP BY GroupID
),
-- DEFINE A CTE TO GET ALL EVENTS FOR THE GROUPS DEFINED ABOVE
AllEvents AS
( SELECT e.*
FROM event e
INNER JOIN Groups m
ON m.GroupID = e.group_id
UNION ALL
SELECT e.event_id, e.title, e.description, DATEADD(WEEK, w.weeks, e.event_start), DATEADD(WEEK, w.weeks, e.event_end), e.group_id, e.recurring
FROM event e
INNER JOIN Groups m
ON m.GroupID = e.group_id
CROSS JOIN
( SELECT ROW_NUMBER() OVER (ORDER BY Object_ID) AS weeks
FROM SYS.OBJECTS
) AS w
WHERE e.recurring = 1
)
-- GET ALL EVENTS WHERE THE EVENTS FALL IN THE PERIOD DEFINED
SELECT *
FROM AllEvents
WHERE Event_Start >= @StartDate
AND Event_End <= @EndDate
END
然后你可以用
来调用它var result = db.Query("EXEC dbo.GetEvents @0, @1, @2", username, start, end);
这使得需要迭代代码中的组。如果这实际上是一个要求,那么您可以修改存储过程以将@GroupID作为参数,并根据需要更改select语句/ where子句。
我已经了解Common Table Expressions。他们不需要使查询工作,他们只是让我认为更容易辨认。如果需要,我可以在没有它们的情况下重写它。