复杂的SQL Server查询

时间:2012-03-12 20:05:06

标签: c# sql sql-server database

我正在尝试编写一个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周的事件。当在这一周之后的一周查询事件时,不会返回任何内容。

2 个答案:

答案 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。他们不需要使查询工作,他们只是让我认为更容易辨认。如果需要,我可以在没有它们的情况下重写它。