繁体   English   中英

SQL 服务器 - 基于条件的 SUM() 和 Group() 记录

[英]SQL Server - SUM() and Group() Records based on a condition

在我的游戏应用程序中,我有团队,每个团队可以有任意数量的玩家; 如果一个球员参加了一场比赛,我给他 5 分。 每次玩家参加一场比赛,他将获得 5 分。

我的存储过程将TeamId作为输入参数。

现在我想按月计算每支球队获得的总参与积分,但是这里每个球员获得的参与积分应该添加到该球员参加比赛的最后一个月。

假设Team1 Player1 Player1总共打了 4 场比赛,1 场比赛在 04/2020,2 场比赛在 06/2020 和 1 场比赛在 08/2020,在这里打了 4 场比赛, Team1 Player1了 20 参与点数,最后一场Player1 的比赛是在 08/2020 进行的,所以 Team1 的所有 20 分都应该加到 08/2020

在每个玩家的玩家表中,我有每个玩家的 [TotalMatchesPlayed],[TotalMatchesPlayed] * 5 会给我每个玩家的 [TotalParticipationPoints]。

这应该对团队中的所有玩家重复。

    SELECT SUM(ISNULL(P.[TotalMatchesPlayed], 0) * 5) AS [ParticipationPoints], CAST(MONTH(PA.[ActivityDate]) AS VARCHAR(2)) AS [Month], CAST(YEAR(PA.[ActivityDate]) AS VARCHAR(4)) AS [Year] FROM [TeamPlayer] TP
INNER JOIN dbo.[Player] P
ON TP.[PlayerId] = P.[PlayerId]
INNER JOIN dbo.[PlayerActivity] PA
ON PA.[PlayerId] = P.[PlayerId] AND PA.[PlayerActivityTyepId] = 14
WHERE TP.[TeamId] = 45
GROUP BY CAST(MONTH(PA.[ActivityDate]) AS VARCHAR(2)), CAST(YEAR(PA.[ActivityDate]) AS VARCHAR(4))

我对这个查询的问题是 [PlayerActivity] 表在每次玩家参加比赛时都有一行,现在我只想获取最新日期并将所有参与点数添加到我无法实现的那个月份和年份。

我的样本 output 应该如下所示

ParticipationPoints | Month |  Year
        5                06     2020
       10                11     2020

CREATE TABLE TeamPlayer (
    TeamPlayerID int,
    PlayerId int,
    TeamId INT
);

INSERT INTO TeamPlayer VALUES (1, 101, 45)
INSERT INTO TeamPlayer VALUES (2, 104, 19)
INSERT INTO TeamPlayer VALUES (3, 108, 45)

CREATE TABLE Player (
    PlayerID int,
    FirstName VARCHAR(1000),
    LastName VARCHAR(1000),
    [TotalMatchesPlayed] INT
);

INSERT INTO Player VALUES (101, 'Joe', 'Abbey', 2)
INSERT INTO Player VALUES (102, 'Vince', 'Abbott', 3)
INSERT INTO Player VALUES (103, 'Duke', 'Abbruzzi', 7)
INSERT INTO Player VALUES (104, 'Kamlesh', 'Abu', 9)
INSERT INTO Player VALUES (105, 'Evika', 'Abram', 0)
INSERT INTO Player VALUES (106, 'Prince', 'Subtle', 2)
INSERT INTO Player VALUES (107, 'Dick', 'Absher', 1)
INSERT INTO Player VALUES (108, 'George', 'Abrell', 1)
INSERT INTO Player VALUES (109, 'William', 'Peck', 2)
INSERT INTO Player VALUES (110, 'Aaron', 'Adams', 0)

CREATE TABLE PlayerActivity (
    PlayerActivityId int,
    PlayerId int,
    PlayerActivityTyepId INT,
    ActivityDate DATE
);

INSERT INTO PlayerActivity VALUES (1, 101, 14, '2020-04-21')
INSERT INTO PlayerActivity VALUES (2, 108, 14, '2020-06-17')
INSERT INTO PlayerActivity VALUES (3, 101, 14, '2020-11-24')

下面链接中的示例表设计和示例数据与我的查询。

http://sqlfiddle.com/#!18/870f92/1

再次重申,如果球队中的一名球员参加了多场比赛,比如 6 场,我需要在他参加最后一场比赛的月份上增加 6*5 = 30 分。

我的解决方案使用一个子查询来确定每个玩家的最后活动日期

SELECT
    PlayerId,
    MAX(ActivityDate) AS LastDate
FROM
    dbo.PlayerActivity
WHERE PlayerActivityTyepId = 14
GROUP BY PlayerId

主查询也使用 GROUP BY 来聚合每个团队和年/月的结果。 技巧是在 CASE 表达式中完成的。 这里我将实际活动日期与子查询确定的最后一个进行比较。 点数仅归因于最后一个活动,否则为 0。

SELECT
    TP.TeamId,
    SUM(
        CASE
           WHEN PA.ActivityDate = X.LastDate
           THEN P.TotalMatchesPlayed * 5
           ELSE 0
        END
    ) AS ParticipationPoints,
    RIGHT(CAST(100+MONTH(PA.ActivityDate) AS VARCHAR(3)), 2) AS [Month],
    CAST(YEAR(PA.ActivityDate) AS VARCHAR(4)) AS [Year]
FROM
    dbo.TeamPlayer TP
    INNER JOIN dbo.Player P
        ON TP.PlayerId = P.PlayerId
    INNER JOIN dbo.PlayerActivity PA
        ON PA.PlayerId = P.PlayerId AND PA.PlayerActivityTyepId = 14
    INNER JOIN (
        SELECT
            PlayerId,
            MAX(ActivityDate) AS LastDate
        FROM
            dbo.PlayerActivity
        WHERE PlayerActivityTyepId = 14
        GROUP BY PlayerId
    ) AS X
        ON X.PlayerId = P.PlayerId
WHERE TP.TeamId = 45
GROUP BY
    TP.TeamId, YEAR(PA.ActivityDate), MONTH(PA.ActivityDate)

http://sqlfiddle.com/#!18/41766/28/0

请注意,我假设每个玩家每天只有一项活动。 多了就反复总结分。 如果PlayerActivityId值严格按升序插入,您可以通过使用MAX(PlayerActivityId)而不是MAX(ActivityDate)来解决此问题。

为了获得两位数的月份,我首先计算 month+100 并将其转换为VARCHAR(3) 这会产生四月份'104' 然后我通过返回最后两个字符RIGHT function 得到结果。当然,您可以使用适当的格式化函数,但我懒得查找要使用的正确函数和格式。

您可以使用 window 功能:

select year(activitydate) as yyyy, month(activitydate) as mm, 
    sum(cnt) * 5 as partitionpoints
from (
    select pa.*, 
        count(*) over(partition by playerid) cnt,
        row_number() over(partition by playerid order by activitydate desc) rn
    from playeractivity pa
) t
where rn = 1
group by year(activitydate), month(activitydate)
order by yyyy, mm

子查询计算每个玩家的活动总数,并将每个玩家的记录从最新到最旧排列。 外部查询过滤最新记录,按年和月聚合并进行计算。

DB Fiddle 演示

yyyy | mm | partitionpoints
---: | -: | --------------:
2020 |  6 |               5
2020 | 11 |              10

请注意,我们可以通过仅查看活动表来获得此结果。 看起来我们不需要 teams 表,也不需要 player 表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM