试图在 SQL Server 中找到总和的中位数

Posted

技术标签:

【中文标题】试图在 SQL Server 中找到总和的中位数【英文标题】:Trying to find the median of a sum in SQL Server 【发布时间】:2020-10-27 21:06:29 【问题描述】:

我正在尝试查找我的类别 EVS 的月中位数。为此,我需要总结每个逻辑设备名称的所有事件。但是,这需要每月进行一次。我有两个查询第一个,我将在下面粘贴,每天总结该机器人的所有事件,但我需要进一步总结以使其每月一次。此外,我需要在多年内每月执行一次。

select logicalDeviceName, Sum(Events) as consolidatedEvents, EVS, StartDate
From report.DisinfectionStatsCombined
group By LogicalDeviceName, EVS, StartDate
Order By EVS 

结果是这样的

This is a sample of my outcome, as you can see I need a single row to be apollo with a sum of the all the consolidated events for that one month

此外,这是我尝试使用结果样本计算中位数的代码。

select logicalDeviceName, Sum(Events) as consolidatedEvents, EVS, StartDate,
PERCENTILE_CONT(0.5) within group (order by Sum(Events))
OVER (Partition BY year(StartDate),Month(StartDate),EVS) AS MedianCont
From report.DisinfectionStatsCombined
group By LogicalDeviceName, EVS, StartDate,Events
Order By EVS 

As you can see the outcome is far from desirable and the consolidated events numbers change to be incorrect. I think the numbers from the first query are correct but then the change significantly here, why is that?

我再次尝试通过按每个逻辑设备名称汇总所有合并事件来计算中位数。所以每个月应该只有一个名字。然后,我将使用这些信息每月计算每个 evs 的中位数。有 4 种 evs 类型,我将提供另一种类型的片段。我觉得我可能必须更改分组,以显示不同类型的 ev。理想情况下,我只想将它按月/年分组。日期可以追溯到 2012 年。

picture to show example of the other evs

以下是我想要的结果示例 sample outcome and data

【问题讨论】:

请将示例显示为文本。 【参考方案1】:

我对您的目标的理解:

    计算每月每个 LogicalDeviceName 的事件计数 计算每个 LogicalDeviceName 每月事件的中位数 计算每个 EVS 每月事件的中位数

我的工作假设是,对于任何给定的 LogicalDeviceName,只有一个匹配的 EVS。例如,当 LogicalDeviceName 值为“Apollo”时,EVS 值将始终为“Commercial”。

请注意,我创建并填充了测试表以获取下面的屏幕截图。脚本包含在下面。

目标 1:汇总每个 LogicalDeviceName 每月的事件计数,以回答“2015 年 1 月 Apollo 发生了多少事件?”之类的问题。像这样的查询应该可以解决问题。将年和月部分与日分开允许月聚合:

SELECT 
      LogicalDeviceName
    , SUM(Events) [ConsolidatedEvents]
    , EVS
    , FORMAT(StartDate, 'yyyy/MM') [YearAndMonth]
FROM [Test]
GROUP BY 
      LogicalDeviceName
    , EVS
    , FORMAT(StartDate, 'yyyy/MM')
ORDER BY 
      YearAndMonth DESC
    , LogicalDeviceName

目标 2:计算每个 LogicalDeviceName 每月事件的中位数

SELECT DISTINCT
      LogicalDeviceName
    , PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY Events) 
        OVER (PARTITION BY LogicalDeviceName, YEAR(StartDate), MONTH(StartDate)) [Median]
    , FORMAT(StartDate, 'yyyy/MM') [YearAndMonth]
FROM [Test]
ORDER BY [YearAndMonth] DESC, LogicalDeviceName

需要使用 DISTINCT 因为PARTITION BY includes a row for each record。另请注意,虽然这种语法更简单,但 there are potentially more performant ways to calculate median.

目标 3:使用每个 LogicalDeviceName 的事件“合并”(SUM) 计算每个 EVS 每月事件的中位数

这就是我对你想要完成的事情感到有点模糊的地方。如果提供进一步说明,将更新。根据提供的前/后组屏幕截图在下面进行编辑。在我的脑海中,CTE 构建第一个查询是最简单的方法:

WITH Consolidated AS
(
    SELECT 
          LogicalDeviceName
        , SUM(Events) [ConsolidatedEvents]
        , EVS
        , FORMAT(StartDate, 'yyyy/MM') [YearAndMonth]
    FROM [Test]
    GROUP BY 
          LogicalDeviceName
        , EVS
        , FORMAT(StartDate, 'yyyy/MM')
)
SELECT DISTINCT
    EVS
    , PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY ConsolidatedEvents)
        OVER (PARTITION BY EVS, YearAndMonth) [Median]
    , YearAndMonth
FROM Consolidated
ORDER BY YearAndMonth DESC, EVS

测试表创建/填充脚本:

SET NOCOUNT ON
GO
CREATE TABLE [Test]
(
      LogicalDeviceName VARCHAR(64)
    , Events INT
    , EVS VARCHAR(16)
    , StartDate DATETIME2
)

GO

DECLARE @LDN_EVS_Pairs TABLE
(
      LDN VARCHAR(16)
    , EVS VARCHAR(16)
)

INSERT INTO @LDN_EVS_Pairs(LDN, EVS)
VALUES
      ('Apollo', 'Commercial')
    , ('Appleton1', 'Commercial')
    , ('Baptist Beaches', 'Sodexo')
    , ('Florida Hospital', 'Commercial')
    , ('FROST', 'VA/DoD')
    , ('FVAMC1', 'VA/DoD')
    , ('GERMN8R', 'Commercial')
    , ('Glady', 'Commercial')
    , ('Sheldon', 'Sodexo')

DECLARE 
      @Counter INT = 10000
    , @Multiplier INT
    , @CurrentLDN VARCHAR(16)
    , @CurrentEvents INT
    , @CurrentEVS VARCHAR(16)
    , @CurrentStartDate DATETIME2
    , @MinEvents INT = 0
    , @MaxEvents INT = 50
    , @MinDate DATE = '20120101'
    , @MaxDate DATE = '20200707'

WHILE (@Counter > 0)
BEGIN
    SELECT TOP(1)
          @Multiplier = ABS(CHECKSUM(NEWID()) % (@MaxEvents/2 - @MinEvents + 1)) + @MinEvents
        , @CurrentLDN = LDN
        , @CurrentEvents = ABS(CHECKSUM(NEWID()) % (@MaxEvents - @MinEvents + 1)) + @MinEvents
        , @CurrentEVS = EVS
        , @CurrentStartDate = DATEADD(DAY,ABS(CHECKSUM(NEWID())) % (1+DATEDIFF(DAY,@MinDate,@MaxDate)),@MinDate)
    FROM @LDN_EVS_Pairs
    ORDER BY NEWID()

    WHILE(@Multiplier > 0)
    BEGIN
        INSERT INTO [Test](LogicalDeviceName, Events, EVS, StartDate)
        VALUES(@CurrentLDN, @CurrentEvents, @CurrentEVS, @CurrentStartDate)
        
        SET @Multiplier -= 1
    END
    SET @Counter -= 1
END

this SO Post 为生成随机值提供了一点帮助。

【讨论】:

您好,感谢您尝试回答。我可能在解释方面做得不好。但是我要做的是以下内容。1)我需要计算数据集中每年每个月的每个逻辑设备名称的合并事件。从 2012 年 1 月到 2020 年 1 月将有实例。2)完成此操作后,我需要获取数据集中每年每个月的 4 个 evs 提供者中每个的合并事件的中位数。月份和年份也需要在同一列中。 但是非常感谢你,这本身就非常有帮助!!!!! 您制作的第一张表是我想要的结果,从那时起,我想计算每个月每个 evs 的合并事件的中位数。换句话说,我的最终结果需要是那个月/年的 evs 的中位数。因此,我想选择 evs 在该组中间的那一个月的逻辑设备号。 我编辑在一列中有年份和月份日期部分。关于最终结果,我仍然难以理解。请提供小的起始示例数据集和该数据集的预期结果以帮助理解。

以上是关于试图在 SQL Server 中找到总和的中位数的主要内容,如果未能解决你的问题,请参考以下文章

使用带有 ORDER BY 的 SQL Server 查找累积总和

在 SQL Server 中使用 group by 的列名总和?

在 SQL Server 中计算中位数的函数

在 SQL Server 中使用逐行总和进行透视[关闭]

在SQL Server中显示上半年和下半年的销量总和以及总销量

前 3 个月的滚动总和 SQL Server