一些同行的代码审阅者(嗨@Janos!)一直在查询SEDE查询,以检查Red Shirt“ hat”进程的进度。

在这里尝试!


背景




红色衬衫
/>
对后来被删除或关闭的帖子进行5次否决投票



限制

有某些Stack Exchange限制使查询此信息有些棘手。即:


每周仅在星期日刷新一次数据。这样就不可能获得“实时”结果。
用户投票活动是匿名的,因为用户只能在自己的个人资料中看到自己的投票活动。这不允许在SEDE上加入投票和用户数据。

假设

我已经根据一些普遍的未解决问题的趋势做出了某些假设。他们是:


投票关闭/删除错误问题的用户通常也会对该问题投反对票。
投票拒绝问题的用户通常会在对关闭/删除。

用法

要从中获得有用性(如查询顶部的SQL注释所示):


使用此报告的方式是将结果集
与活动报告下的“投票”并排比较。
按向下投票进行过滤并查看查看下面的结果集中是否是您否决的问题。


例如:



查询

/* 
Winter Bash 2014
"Red Shirt" hat estimation
"Cast 5 downvotes on posts that are later deleted or closed"

The way that this report can be used is by comparing the results set 
side-by-side with your "votes" under your activity reports.
Filter by down-votes and look to see if questions you down-voted are
in the result set below.
*/

-- NumberWeeks: Number of weeks to go back

-- DATETIME VARIABLES

DECLARE @today DATETIME;
SET @today = CURRENT_TIMESTAMP;

DECLARE @weeks_ago INT;
SET @weeks_ago = ##NumberWeeks:int?4##;
-- Number of weeks must not go into the future, hence the following:
SET @weeks_ago = (CASE WHEN @weeks_ago >0 THEN -@weeks_ago ELSE @weeks_ago END);

DECLARE @target_week DATETIME;
SET @target_week = DATEADD(WEEK, @weeks_ago, CURRENT_TIMESTAMP);

-- POST-RELATED VARIABLES

DECLARE @downvote TINYINT;
SET @downvote = (SELECT Id FROM VoteTypes WHERE Name LIKE 'Down%'); --3

DECLARE @question_post TINYINT;
SET @question_post = (SELECT Id FROM PostTypes WHERE Name = 'Question'); --1

DECLARE @closed_post TINYINT;
SET @closed_post = (SELECT Id FROM PostHistoryTypes WHERE Name = 'Post Closed'); --10

DECLARE @deleted_post TINYINT;
SET @closed_post = (SELECT Id FROM PostHistoryTypes WHERE Name = 'Post Deleted'); --12

-- QUERY BEGINS

WITH cte_downvoted_posts AS
(
  SELECT Votes.PostId AS dvote
  FROM Votes
  INNER JOIN Posts ON Votes.PostId = Posts.Id
  WHERE VoteTypeId = @downvote
)

SELECT 
    Posts.Id AS [Post Link]               -- magic column
  , Posts.OwnerUserId AS [User Link]      -- magic column
  , Posts.CreationDate AS [Creation Date]
  , Posts.ClosedDate AS [Closed Date]

FROM Posts
INNER JOIN cte_downvoted_posts
    ON Posts.Id = cte_downvoted_posts.dvote
INNER JOIN PostHistory
    ON Posts.Id = PostHistory.PostId

WHERE Posts.CreationDate <= @today
  AND Posts.CreationDate > @target_week
  AND Posts.PostTypeId = @question_post
  AND Posts.ClosedDate IS NOT NULL

GROUP BY
    Posts.Id
  , Posts.OwnerUserId
  , Posts.CreationDate
  , Posts.ClosedDate

ORDER BY
    Posts.CreationDate DESC


关注事项


细刺很好!从命名到缩进再到不一致,请不要羞于指出任何东西!
执行连接时,我注意到执行计划中有很多嵌套循环。有没有更好的方法来避免这种情况?
有没有办法使此查询结果集更有用或更用户友好?
我的评论适当/有用吗?我应该更少还是更多?


#1 楼


您完全不需要在CTE中加入帖子,因为您无需使用其任何列,并且从主查询中获得“帖子必须存在”的要求。
相同行,您根本不会在查询中使用PostHistory,而是将其全部加入。
您声明了@deleted_post,但从未使用过;您只需将@closed_post设置两次(可能第二次错误地将其设置为“已删除帖子”行的ID。)
但是再一次,您在查询中没有使用@closed_post或@deleted_post,所以为什么会得到到底是什么?
一些无1-2测试会揭示SE是否曾经以“ Down”开头添加新的表决类型,因为您假设@downvote变量仅被分配了一个标量值,因此查询将失败。因此,可以将TOP 1添加到查询中,或者将WHERE子句更改为=运算符,以防止出现这种情况。 (此外,由于您仅搜索“ DownMod”投票类型,为什么首先要使用LIKE运算符?)

我完全删除了CTE,并将您的主查询更改为:

SELECT 
    Posts.Id AS [Post Link]               -- magic column
  , Posts.OwnerUserId AS [User Link]      -- magic column
  , Posts.CreationDate AS [Creation Date]
  , Posts.ClosedDate AS [Closed Date]

FROM Posts
INNER JOIN Votes
    ON Posts.Id = Votes.PostId

WHERE Posts.CreationDate <= @today
  AND Posts.CreationDate > @target_week
  AND Posts.PostTypeId = @question_post
  AND Posts.ClosedDate IS NOT NULL
  AND VoteTypeId = @downvote

GROUP BY
    Posts.Id
  , Posts.OwnerUserId
  , Posts.CreationDate
  , Posts.ClosedDate

ORDER BY
    Posts.CreationDate DESC


就我个人而言,我只需要调用您的Top 1子查询即可直接在查询中获取DownMod VotetypeID和Question PostTypeID,但这仅是出于宗教目的。

评论


\ $ \ begingroup \ $
我确实注意到我遗留了以前打算使用的一些变量,它来自一个较旧的版本,但效果不是很好。不错的收获和不错的评论!
\ $ \ endgroup \ $
– ran
2014年12月20日15:57

#2 楼

我发现这做得很好,而且很难选择。
但是这里有一些东西。
而不是这样写这个条件:


WHERE Posts.CreationDate <= @today
  AND Posts.CreationDate > @target_week



这更短更简单:

WHERE Posts.CreationDate BETWEEN @target_week AND @today


请记住,尽管这并不完全相同,
因为我没记错,
BETWEEN使用<=>=条件。
但是即使这样,在此查询的情况下也可能没有任何区别。
(我确认有1周的时间可以返回,结果是相同的。)

顺便说一句,@ Malachi指出了一篇有关范围查询及其危险的出色文章。

nitpick非常小,但是在此列别名中,我会很好地将“ dvote”拼写为“ downvote”:


  SELECT Votes.PostId AS dvote



评论


\ $ \ begingroup \ $
这两个where语句不相同。之间有点奇怪,它的作用类似于WHERE x otherDate,并且不包括开始日期和结束日期。
\ $ \ endgroup \ $
–马拉奇♦
2014年12月19日在20:22

\ $ \ begingroup \ $
StackOverflow上有几篇文章。你稍等一会儿。看起来这个答案说的话与我说的话有些不同,您怎么看? stackoverflow.com/a/16347680/1214743
\ $ \ endgroup \ $
–马拉奇♦
2014年12月19日20:25



\ $ \ begingroup \ $
Aaron Bertrand在SO上非常出名,因此他的博客非常全面地谈论了Dates和SQL Server。 sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/…
\ $ \ endgroup \ $
–马拉奇♦
2014-12-19 20:31



#3 楼


-- Number of weeks must not go into the future, hence the following:
SET @weeks_ago = (CASE WHEN @weeks_ago >0 THEN -@weeks_ago ELSE @weeks_ago END);



归结为取给定参数的绝对值,因此可以简化为:

SET @weeks_ago = abs(@weeks_ago)


我希望查询为无效的参数值返回0行。

评论


\ $ \ begingroup \ $
我从未听说过ABS()是个好主意!
\ $ \ endgroup \ $
– ran
2014年12月19日20:30在

#4 楼

注释

-- NumberWeeks: Number of weeks to go back

-- DATETIME VARIABLES

DECLARE @today DATETIME;
SET @today = CURRENT_TIMESTAMP;

DECLARE @weeks_ago INT;
SET @weeks_ago = ##NumberWeeks:int?4##;



关于周数的注释应该更接近于声明。
更好的变量名将消除对完全是这个变量。


SELECT 
    Posts.Id AS [Post Link]               -- magic column
  , Posts.OwnerUserId AS [User Link]      -- magic column


好吧,这是一个神奇的专栏吗?魔术专栏有什么作用? (对于那些不知道的人,这会使特殊的列显示为超链接。)

评论


\ $ \ begingroup \ $
魔术列是特定于种子的...任何使用sede的人都可能偶然发现了它们。
\ $ \ endgroup \ $
–Vogel612♦
2014年12月19日20:52

\ $ \ begingroup \ $
也许@ Vogel612。也许不吧。那是做什么的
\ $ \ endgroup \ $
–RubberDuck
2014年12月19日20:54



#5 楼

通用表表达式出于所有目的和目的,是一个表,应相应命名,


WITH cte_downvoted_posts AS



应为

WITH DownvotedPosts AS


放弃匈牙利命名风格,并与Pascal一起使用诸如表和列之类的大牌商品。

数据库中的所有对象都应为Pascal(我认为)

评论


\ $ \ begingroup \ $
足够公平..但是从技术上讲CTE不是数据库对象。
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年12月19日在20:13

\ $ \ begingroup \ $
我们在这里谈论技术如何?这是一个临时表,在事务处理后被销毁。 @杯垫
\ $ \ endgroup \ $
–马拉奇♦
2014年12月19日在20:16

#6 楼

这不仅仅是功能检查,而不仅仅是适当的代码审查,但允许用户选择要过滤或排序的特定主题可能会更好。

此外,这可能是一种较快捷的检查方法自己的历史记录只需单击问题链接即可。如果您投票否决,该问题的“投票否决”按钮将突出显示。

评论


\ $ \ begingroup \ $
好主意,也许添加标签作为选项会很好!
\ $ \ endgroup \ $
– ran
2014年12月19日20:28在

\ $ \ begingroup \ $
我已经将此查询修改为按第一个标记排序的查询。
\ $ \ endgroup \ $
–爱德华
2014年12月19日在20:42