【问题标题】:Moving grouped MEDIAN / Get the MEDIAN of specific months from the past IN T-SQL移动分组 MEDIAN / 从过去的 T-SQL 中获取特定月份的 MEDIAN
【发布时间】:2021-08-17 06:51:03
【问题描述】:

假设我有一张桌子:

DATE ID VALUE
01.2010 1 100
02.2010 1 200
... ... ...
12.2010 1 300
01.2011 1 150
02.2011 1 250
... ... ...
12.2011 1 350
01.2012 1 200
02.2012 1 300
... ... ...
12.2012 1 400

我想获得按月分组的 VALUE 的中位数,即获得类似

DATE ID VALUE MEDIAN
01.2010 1 100 100
02.2010 1 200 200
... ... ... ...
12.2010 1 300 300
01.2011 1 150 125 = (100+150)/2
02.2011 1 250 225 = (200+250)/2
... ... ... ...
12.2011 1 350 325 = (300+350)/2
01.2012 1 200 150
02.2012 1 300 250
... ... ... ...
12.2012 1 400 350

我在表格中有更多 ID,因此我想为每个 ID 获取此结果。

我试过了

SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY VALUE) OVER (PARTITION BY Id, MONTH(Date) ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)

但我得到“函数 'PERCENTILE_CONT' 可能没有窗口框架。

我也尝试了以下方法(但也没有任何结果):

SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY VALUE)
OVER (PARTITION BY Id, MONTH(Date)) 
FROM tab1 LEFT JOIN tab2 
ON tab1.key = tab2.key
WHERE tab1.Date BETWEEN Min(Date) AND tab2.Date

编辑 到目前为止,我已经解决了

SELECT (CASE WHEN Date =2010 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date = 2010 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date))  ELSE 0 END) + 
(CASE WHEN Date =2011 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date <= 2011 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date))  ELSE 0 END) + 
(CASE WHEN Date =2012 THEN PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY CASE WHEN Date <= 2012 THEN VALUE ELSE NULL) OVER (PARTITION BY Id, MONTH(Date))  ELSE 0 END)
FROM tab1

但老实说,我希望在不假设日期的先验知识的情况下做出解决方案。我考虑过 WHILE LOOP 和更新列 while @MinYear

【问题讨论】:

    标签: tsql grouping median


    【解决方案1】:

    我的想法是使用 (Value1+value2)/2 作为中位数,因为您的要求有点复杂。

     CREATE TABLE MedianData
      (   
      [Date] VARCHAR(100)
      ,ID INT 
      ,[Value] INT
     )
    
     INSERT INTO MedianData VALUES  ('01.2010', 1,  100)
        ,('02.2010',    1,  200)
        ,('12.2010',    1,  300)
        ,('01.2011',    1,  150)
        ,('02.2011',    1,  250)
        ,('12.2011',    1,  350)
        ,('01.2012',    1,  200)
        ,('02.2012',    1,  300)
        ,('12.2012',    1,  400)
    
     SELECT * 
           ,ROW_NUMBER() OVER  ( PARTITION BY  Substring([Date],1,2 ) ORDER BY [Date]  ) AS [row]
           ,Substring([Date],1,2 ) as [MONTH]
        INTO #Temp_tbl2
       FROM MedianData 
    
     SELECT
        A.Date
        ,A.ID
        ,A.[Value] 
       --Logic is applied here. I used (Value1+value2)/2 as median
       ,CASE WHEN A.[row] = 3   THEN  ( A.[Value] +  (    SELECT T.[Value] FROM #Temp_tbl2 
                        T where T.[MONTH] =  Substring(A.[Date],1,2 ) AND T.[row]  = 1 ) )/2 
        WHEN  A.[row] != 1 THEN  (A.total/2) 
        ELSE A.total END as [Median]
       INTO #Temp_table
      FROM
        (
         SELECT * 
        ,ROW_NUMBER() OVER  ( PARTITION BY  Substring([Date],1,2 ) ORDER BY [Date]  ) AS [row] 
    
         ,SUM ([Value] )   OVER  (  PARTITION BY  Substring([Date],1,2 ) ORDER BY [Date] ) AS [total] 
           FROM MedianData
        ) AS A
    
      --to make the table data order
        SELECT MedianData.*, #Temp_table.Median
        FROM MedianData
        INNER JOIN #Temp_table
             ON MedianData.[Date] =  #Temp_table.[Date] 
    
      drop table #Temp_table
      drop table #Temp_tbl2
    

    【讨论】:

    • 由于我得到了分辨率,我还没有在我的装置上尝试过,但这看起来也很棒。谢谢你的回答!
    猜你喜欢
    • 2020-08-02
    • 2021-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多