【问题标题】:Error with single SQL query单个 SQL 查询出错
【发布时间】:2012-03-09 21:11:22
【问题描述】:

我正在尝试为我的数据库编写一个 SQL 查询,该查询将检索所有特定用户事件。如果它们被标记为重复出现,我希望它们在开始日期后的 52 周内每周出现一次。有没有更好的方法来做到这一点?我当前的代码看起来很笨重。

我的表格结构如下:

   event (
    event_id INT NOT NULL AUTO_INCREMENT, (PK)
    title VARCHAR(80) NOT NULL,
    description VARCHAR(200),
    event_start DATETIME,
    event_end DATETIME,
    group_id INT NOT NULL,
    recurring BOOLEAN
);

   Users{
    UserID (PK)
    Username
   }

   Groups{
    GroupID (PK)
    GroupName
   }

   Membership{
    UserID (FK)
    GroupID (FK)
   }

这是我目前的查询,目前无法使用,有人可以帮我吗?

 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
            AND    m.UserID = ?
            AND    e.event_start >= ?
            AND    e.event_end <= ?
            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,
            (SELECT row_number() OVER (ORDER BY Object_ID) AS weeks
                    FROM SYS.OBJECTS) AS w
            WHERE  NOT e.recurring
            AND    m.user_id = ?
            AND    e.event_start >= ?
            AND    e.event_end <= ?", username, start, end, username, start, end
        );

谁能帮我调整我的代码,使其选择所有不重复的事件,并在 52 周内同时选择重复事件?

【问题讨论】:

  • 附带说明,请记住一年没有 52 周。
  • 52.177457 周!不过,它更容易四舍五入,不是吗?! :)
  • 我已经看到系统在每次没有 52 周的情况下,都会在盲目恐慌中获得另外几个丑陋的黑客攻击。
  • 希望那时我能够避免这种情况! :)
  • 查询的实际结果与您想要的结果有何不同?

标签: sql sql-server database relational-database


【解决方案1】:

可能是这样的:

SELECT e.event_id, e.title, e.description, e.start_time, e.end_time
     , e.group_id, e.recurring
FROM   Events e
JOIN   Membership m ON m.groupid = e.group_id
WHERE  e.recurring = 0 
AND    m.user_id = ?
AND    e.start_time >= ?
AND    e.end_time <= ?

UNION ALL
SELECT e.event_ID, e.title, e.description
      ,DATEADD(week, w.weeks, e.start_time) -- AS event_start
      ,DATEADD(week, w.weeks, e.end_time)   -- AS event_end
      ,e.group_id, e.recurring
FROM   Events e
JOIN   Membership m ON m.groupid = e.group_id
      ,(SELECT row_number() OVER (ORDER BY Object_ID) AS weeks
        FROM SYS.OBJECTS) AS w
WHERE  e.recurring = 1
AND    m.user_id = ?
AND    e.start_time >= ?
AND    e.end_time <= ?
  • 使用UNION ALL 而不是UNION

  • event_startevent_end 而不是 start_timeend_time (??) 我改了。

  • 一开始我也错过了:user_id 在表 Membership 中,所以如果你想在 WHERE 子句中使用它,你需要 JOIN 在里面。外键列似乎是group_id / groupid。 (我会统一拼写!)

  • 您在查询的第一部分中有 SELECT *。最好在这样的查询中拼出列名,否则以后对基础表的更改会以令人惊讶的方式破坏它。

  • 我的初稿有一个辅助函数 generate_series()here 生成数字 1-52 的集合,但您原来的解决方案更好,所以我恢复了这个更改。

【讨论】:

  • 我应该在代码中的何处添加函数 generate_series 以集成它?非常感谢您的回复-当您显示辅助功能时,这让我有点不知所措! :)
  • @SimonKiely:对不起,那个辅助功能实际上是没有必要的。您的原始解决方案更简单。我恢复了该更改。
  • Brandstetter,您好,我尝试将此代码集成到我的系统中并得到错误:“解析查询时出错。[令牌行号 = 4,令牌行偏移量 = 13,令牌错误 = AND ]] "
  • 我已经更新了上面的代码以准确显示我正在运行的内容 - 用户名是一个字符串,开始和结束是日期时间。
  • 我认为错误在于 user_id 列在另一个表中,而不是正在查询的事件表。
【解决方案2】:

试试这个。您在 SQL 中使用了 event_start 和 event_stop,但它们没有在表事件中定义。您唯一混淆的是 start_time = @CurrentTime。我不认为你的代码很笨重。 UNION ALL 比 UNION 执行得更好(UNION 的工作方式类似于 DISTINCT:首先 ORDER BY 然后删除重复项)。

DROP TABLE #Events
CREATE TABLE #Events (
  event_id  INT NOT NULL,
  title VARCHAR(80) NOT NULL,
  description   VARCHAR(200),
  start_time    DATETIME,
  end_time  DATETIME,
  group_id  INT NOT NULL,
  recurring bit
);

INSERT INTO #Events(event_id, title, description, start_time, end_time, group_id, recurring) VALUES
(1, 'meeting1', 'meeting1', '20000101', '20000102', 1, 0),
(2, 'meeting2', 'meeting2', '20120309', '20120310', 1, 0),
(3, 'meeting3', 'meeting3', '20120311', '20120312', 1, 0),
(10, 'meeting10', 'meeting10', '20000101', '20000102', 1, 1),
(20, 'meeting20', 'meeting20', '20120309', '20120310', 1, 1),
(30, 'meeting30', 'meeting30', '20120311', '20120312', 1, 1)

DECLARE @CurrentTime DATETIME
SET @CurrentTime = GETDATE()

SELECT event_id, 
    title,
    description, 
    start_time, 
    end_time, 
    group_id, 
    recurring
FROM #Events 
WHERE recurring = 0 AND 
--  user_id = ? AND 
  start_time <= @CurrentTime AND 
  end_time >= @CurrentTime

UNION ALL

SELECT event_ID, 
  title, 
  description, 
  DATEADD(WEEK, Interval, start_time) [event_start], 
  DATEADD(WEEK, Interval, end_time) [event_end], 
  group_id, 
  recurring
FROM #Events,
  (SELECT ROW_NUMBER() OVER(ORDER BY Object_ID) [Interval]
  FROM SYS.OBJECTS) as T 
WHERE recurring = 1 AND 
  Interval <= 52 AND 
--  user_id = ? AND 
  start_time <= @CurrentTime AND 
  end_time >= @CurrentTime
;

【讨论】:

  • 您好,感谢您的回复。这是非常有帮助的。我目前遇到的问题是 user_id 列包含在成员资格表中。我只想检索与 group_id 包含其 user_id 的用户相关的事件 - 因此成员资格表将包含一个 group_id 和几个 user_id,显示作为特定组成员的所有用户。如果在事件中使用了 group_id,那么我只想检索其中一个用户的事件。
  • >如果在事件中使用 group_id,那么我只想为其中一个用户检索事件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-21
  • 2016-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多