求客户月均市值=当月每天市值累加之和/当月天数。由于非交易日未有持仓记录,非交易日市值沿用上个交易日的市值进行累加。例如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高效多了 :)
同样纯手工编写,没有建立临时表测试,请自行测试调整……