Sql server 每个用户的所有记录和最新记录的SQL总和
我有一张这样的桌子:Sql server 每个用户的所有记录和最新记录的SQL总和,sql-server,Sql Server,我有一张这样的桌子: id memberId memberType points date ---- ------------ ------------- ----------- ------------ 1 1001 type1 5.5 01/01/2015 2 1002 type2 4.2 01/02/2015 3 1002 type2
id memberId memberType points date
---- ------------ ------------- ----------- ------------
1 1001 type1 5.5 01/01/2015
2 1002 type2 4.2 01/02/2015
3 1002 type2 2.1 01/15/2015
4 1001 type2 1.5 01/15/2015
5 1002 type1 3.6 01/17/2015
我需要创建一个SQL视图,该视图将显示每个memberId及其最新memberType的点数总和,如下所示:
memberId Type totalPoints
----------- -------------- -----------
1001 type2 7.0
1002 type1 9.9
我尝试了以下查询:
SELECT memberId, MAX(memberType) as Type, SUM(points) as totalPoints
FROM dbo.PointsEarning
GROUP BY memberId
但当然,这仅在最新类型为max类型时有效。另外,我的一些成员类型纯粹是alpha。如果有人能提供最有效的方法,我将不胜感激,因为我将使用它来处理一个有近3000万条记录的表。Update
在我们在评论中的对话之后,假设没有人手动将值插入到id列(使用设置标识插入
),那么您可以使用它查找最后一条记录。因此,只需使用max(id)
,而不是max(date)
:
注意:这应该为每个成员提供一条记录,并且可能比第一个版本更快(如果id实际上是表的聚集索引)
第一版
一种方法是使用公共表表达式:
;WITH cte AS
(
SELECT memberId, MAX(date) as LastDate, SUM(points) as totalPoints
FROM dbo.PointsEarning
GROUP BY memberId
)
SELECT memberId, memberType, totalPoints
FROM dbo.PointsEarning p
INNER JOIN cte ON(p.memberId = cte.memberId AND p.date = cte.LastDate)
注意:代码是直接在这里编写的,没有经过测试。可能有一些错误。试试这个:
SELECT p.memberId,
(SELECT p2.memberType
FROM PointsEarning p2
WHERE p.memberid = p2.memberid
AND NOT EXISTS(
SELECT 'NEXT'
FROM PointsEarning p3
WHERE p3.memberid = p2.memberid
AND p3.date > p2.date)
) as Type, SUM(p.points) as totalPoints
FROM dbo.PointsEarning p
GROUP BY p.memberId
您可以将子查询与下面的
OVER
子句一起使用:
SELECT memberId,
memberType AS Type,
points AS totalPoints
FROM (SELECT memberId,
memberType,
date,
SUM(points) OVER(PARTITION BY memberId) points,
ROW_NUMBER() OVER(PARTITION BY memberId ORDER BY date DESC) rn
FROM dbo.PointsEarning
)x
WHERE rn = 1
您可以在测试它,我假设对于每个您想要选择该组中最后一个
日期的成员类型的组。您可以为此使用子选择:
SELECT
memberId,
(SELECT TOP 1 memberType from PointsEarning p
WHERE p.memberId = PointsEarning.memberId ORDER BY date desc) as Type,
SUM(points) as totalPoints
FROM dbo.PointsEarning
GROUP BY memberId
根据您的数据,此查询工作正常,但您面临的问题是什么?使用MAX获取成员类型会返回成员1002的错误数据,因为其最新成员类型应为type2。您在第二个子查询->p3.date>p3.date应为p2.date>p3.date时出错。然而,我怀疑2个子查询将导致性能大幅度下降。用一个子查询就可以做到这一点,但我认为cte wi可能有更好的性能。@ZoharPeled:谢谢,我已经修复了;)你为什么要分组?这不行anything@t-clausen.dk忘了删除它,在我尝试提出另一种解决方案并错误地保留之前,已将其删除。谢谢!虽然查询花了将近5分钟才完成,但它仍然有效。在给出的答案中,这实际上运行得最快,但为每个成员返回了多行。我的实际数据涉及每个成员的每个日期的多个事务。我想,在第二个查询中添加distinct将消除多行,但可能会使其工作得更慢……是的。实际上,我尝试过使用distinct,但有些成员仍然返回多行,因为他们在一个日期中有不同memberType的事务。那么,在这种情况下,您如何判断哪一行是最新的?Stanislovas Kalašnikovas和t-clausen.dk都没有解决这个问题,因此他们建议的查询(基本相同)每次在最新日期具有多个成员类型的用户上运行时可能会返回不同的结果。如果这对你来说不是问题,那么很好,但是如果是的话,那么你应该找出如何区分它们。我将“订单日期描述”更改为“订单日期描述,id描述”。我还在想如何对你的查询进行同样的处理,
;WITH CTE as
(
SELECT
SUM(points) OVER (PARTITION BY memberId) totalPoints,
ROW_NUMBER() over (PARTITION BY memberId ORDER BY [date] DESC) rn,
id, memberId, memberType, points, [date]
FROM yourtable
)
SELECT
*
FROM CTE
WHERE rn = 1
SELECT
memberId,
(SELECT TOP 1 memberType from PointsEarning p
WHERE p.memberId = PointsEarning.memberId ORDER BY date desc) as Type,
SUM(points) as totalPoints
FROM dbo.PointsEarning
GROUP BY memberId