在SQL中创建CTE与选择条件

时间:2014-04-22 20:58:03

标签: sql-server tsql triggers

我正在开发一个学校数据库项目,该项目需要基于触发器的解决方案来解决我的数据库所具有的一些可选限制。我的数据库模型代表基于在线的视频观看服务,用户可以访问大量视频(与YouTube类似的原则)。表历史记录为每个用户存储多达100个已查看的视频。我的触发器应该做的是:

  • 删除同一视频和用户的先前条目(或将查看日期更改为当前时间)
  • 插入新条目(或更新现有条目,即可能的第1步)
  • 删除所有早于第100个条目的条目

这是我写的代码:

 CREATE TRIGGER [History_Update] ON dbo.History INSTEAD OF INSERT AS
BEGIN
DECLARE @user_id bigint, @video_id bigint, @history_count smallint 
SELECT @user_id=user_id, @video_id=video_id FROM inserted

DELETE FROM History where user_id = @user_id AND video_id=@video_id
INSERT INTO History(user_id, video_id) VALUES (@user_id, @video_id)

SET @history_count = (select count(*) FROM History WHERE user_id= @user_id AND video_id = @video_id)

IF( @history_count >= 100)
BEGIN
    WITH temp AS (SELECT TOP 1 * FROM History WHERE user_id= @user_id AND video_id=@video_id ORDER BY viewtime ASC) 
    DELETE FROM temp
END
END

现在,我对此几乎没有问题:

  • 使用上面写的CTE或类似的东西更好:

    SET @viewtime = (SELECT TOP 1 viewtime FROM History WHERE user_id= @user_id AND video_id=@video_id ORDER BY viewtime ASC) 
    DELETE FROM History where user_id = @user_id AND video_id=@video_id AND viewtime = @viewtime
    
  • 此外,最好检查历史记录中是否存在特定的用户视频条目,然后更新viewtime属性。此外,由于我使用INSTEAD OF触发器,这会违反任何关于使用此类触发器的规则,因为我不确定我是否理解它。从我在线阅读的内容来看,INSTEAD OF触发器必须在触发器的主体内执行指定的操作。 谢谢!

1 个答案:

答案 0 :(得分:0)

考虑到你的表达式和set之间的选择,我会选择CTE。我发现使用带有子查询的set有点icky。毕竟,以下内容也是如此:

SELECT TOP 1 @viewtime = viewtime
FROM History
WHERE user_id = @user_id AND video_id = @video_id
ORDER BY viewtime ASC; 

换句话说,set是多余的。

此外,将setdelete分开会为竞争条件带来机会。也许另一个查询可能会插入一行或删除您要删除的行。

至于CTE本身,没关系。如果要按特定顺序删除行,则需要CTE(或子查询)。