我有一个表TableA
,数据如下:
PostID PostComments PostTransDate UserID
-----------------------------------------------------------------
10000 VRDFHFGFTR 2013-10-26 21:08:19.817 43434
10000 GFDGDFSDFF 2013-10-26 21:12:32.323 67576
10000 HGFHGFBNBF 2013-10-26 21:43:43.545 3232
10000 JNFNGHFGHG 2013-10-26 21:45:46.656 768
10000 MJHJNGJHGH 2013-10-26 21:56:32.767 9897
10001 XCVGFDGDFG 2013-10-26 22:54:54.868 3424
10001 YTUGFGHHGF 2013-10-26 13:32:54.132 12313
10001 HGFHFGHGHF 2013-10-26 18:08:32.878 6565
在此,我想获得每个UserID,PostComments
最大PostID
值的PostTransDate
。
需要输出:
--------------------------------------------------
PostID PostComments PostTransDate UserID
-----------------------------------------------------------------
10000 MJHJNGJHGH 2013-10-26 21:56:32.767 9897
10001 XCVGFDGDFG 2013-10-26 22:54:54.868 3424
我已经有了获得此问题的疑问。
查询1:
SELECT TT.PostID,TT.PostComments,TT.UserID, TT.PostTransDate
FROM tableA TT WITH(NOLOCK)
INNER JOIN
(
SELECT PostID,MAX(PostTransDate) PostTransDate
FROM tableA T WITH(NOLOCK)
GROUP BY PostID
) T ON T.PostID = TT.PostID AND T.PostTransDate = TT.PostTransDate
查询2:
SELECT *
FROM
(
SELECT PostID,UserID,PostTransDate,T.PostComments,
ROW_NUMBER() OVER(PARTITION BY PostID ORDER BY PostTransDate DESC) RNO
FROM tableA T
) N WHERE RNO = 1
我无法在生产中运行这些查询,因为这些查询非常繁重。如果有人有比此更简化的查询,请发帖。
答案 0 :(得分:4)
不了解您的基础索引结构,以及您是否可以更改它,我建议使用此索引:
CREATE INDEX x ON dbo.TableA(PostID, PostTransDate DESC)
INCLUDE (UserID, PostComments);
这仍然需要扫描来解决现有查询,但它至少会扫描这个索引,这比扫描整个表更有效(假设表中还有其他列未被此引用查询)。
;WITH x AS
(
SELECT PostID, UserID, PostTransDate, PostComments,
rn = ROW_NUMBER() OVER (PARTITION BY PostID ORDER BY PostTransDate DESC)
FROM dbo.TableA
)
SELECT PostID, UserID, PostTransDate, PostComments
FROM x WHERE rn = 1;
如果您想要包含关系(不同用户同时在同一帖子上发表多条评论),只需将ROW_NUMBER()
更改为DENSE_RANK()
(实际上,如果您只是追求过最新的日期,您可以有效地使用RANK()
- 我不确定它们是否有任何不同,但它会为您节省6个字符)。如果您不想包含关系,可以通过在OVER()
内添加一个额外的列来预测它们 - 例如,如果您希望用户具有最长的任期,您可以通过{在降序发布日期之后{1}}。
另一个想法是,如果你不能改变索引或者这没有提供足够的提升,那就是在另一个表中实现结果。您可以使用触发器轻松处理此问题,但它会影响您的DML工作负载,因此您不应该只修复此查询。它实际上可能会使您的应用程序性能变差。当然,除非您在此表中实现此查询的所有数据(并且这将是非常多余的),否则它可能无法正常工作,因为为了从主表中检索数据,您仍然必须加入到它,你仍然可能需要在较大的表上进行扫描才能这样做。如果主表有一个IDENTITY列或一些其他主键,这可能会使事情变得更容易和更有效,但在完全理解底层结构之前,我不打算开始编写解决方案。
答案 1 :(得分:1)
试试这个:
SELECT ta1.* FROM tableA ta1
LEFT JOIN tableA ta2
ON ta1.postId = ta2.postId AND ta1.postTransDate < ta2.postTransDate
WHERE ta2.postTransDate IS NULL
输出:
| POSTID | POSTCOMMENTS | POSTTRANSDATE | USERID |
|--------|--------------|--------------------------------|--------|
| 10000 | MJHJNGJHGH | October, 26 2013 21:56:32+0000 | 9897 |
| 10001 | XCVGFDGDFG | October, 26 2013 22:54:54+0000 | 3424 |
FIddle here