MySQL,oracle:求客户月均市值=当月每天市值累加之和/当月天数

img

求客户月均市值=当月每天市值累加之和/当月天数。由于非交易日未有持仓记录,非交易日市值沿用上个交易日的市值进行累加。例如12月4号、5号需用12月3号的市值

请问要怎么写?请指导下。

你是想问oracle里怎么写还是mysql里怎么写?这两个数据库支持的语法不一样。另外请给出数据库版本。
最好能把create table 和insert数据也给一份,省得回答问题的人都还要自己去造数据模拟测试


oracle里可以使用开窗函数lag获取上一行,并且支持通过加关键词的方法来实现获取上一行不为空的值,在这篇帖子里有类似的场景
https://bbs.csdn.net/topics/605261646

以日历为主表,外关联持仓表,当本行市值为空时,获取上一个不为空的市值到本行,最后按月份求和除以天数就好了

WITH sh AS ( -- 每个客户每个交易日的市值
        SELECT date_id, cust_no, sum( mark_value ) mv FROM share GROUP BY date_id, cust_no )
    , dt AS ( -- 每个客户每个非交易日的市值(有冗余)
        SELECT td.date_id, sh.cust_no, sh.mv
              , ROW_NUMBER( ) OVER( PARTITION BY td.date_id, sh.cust_no ORDER BY sh.date_id DESC ) rn
          FROM trade_date td LEFT JOIN sh ON td.date_id > sh.date_id
         WHERE trd_flag = 0 )
    , bs AS ( -- 所有日期的基础数据
        SELECT substr( date_id, 1, 6 ) mon, cust_no, mv FROM sh
        UNION ALL
        SELECT substr( date_id, 1, 6 ) mon, cust_no, mv FROM dt WHERE rn = 1 )
SELECT cust_no, mon, avg( mv ) cust_mon_avg
  FROM bs
 GROUP BY cust_no, mon
 ORDER BY cust_no, mon;

上述SQL为直接手工编写,未在数据库中跑(没有时间建临时表),思路是没有问题,有问题自己调整或提出来即可
当然,这个可以实现业务需要,但可能不是最高效的
用lag函数需要考虑 像国庆节这样的连续多天都为非工作日的情况,需要变换使用,不能直接使用,明天如果有时间再来看使用lag来编写一个更高效的SQL

补充:

WITH sh AS ( -- 每个客户每个交易日的市值
      SELECT date_id, cust_no, sum( mark_value ) mv FROM share GROUP BY date_id, cust_no )
   , td AS ( -- 构建日期对照
      SELECT date_id
           , ( CASE WHEN trd_flag = 1 THEN date_id
                    ELSE ( SELECT max( date_id ) FROM trade_date t1 WHERE t1.date_id < t0.date_id AND trd_flag = 1 ) END ) date_id1
        FROM trade_date t0 )
   , bs AS ( -- 所有日期的基础数据
      SELECT SUBSTR( td.date_id, 1, 6 ) mon, cust_no, mv
        FROM td LEFT JOIN sh ON td.date_id1 = sh.date_id ) -- 注意这里使用的是:date_id1进行的关联
SELECT cust_no, mon, AVG( mv ) cust_mon_avg
  FROM bs
 GROUP BY cust_no, mon
 ORDER BY cust_no, mon;

这样明显比之前的SQL高效多了 :)

同样纯手工编写,没有建立临时表测试,请自行测试调整……