工作中遇到了个问题:要用MySQL求投资人在第二次投资所在的那个月的所有投资金额(以下简称二投金额)。
举例说明:fff4d7d1752f4950b088c5b550a82ac9的二投金额,即为2016-02月份所有投资金额,也就是1500元。如下图所示:
那么怎么写SQL呐?先说一下求一个人的二投金额的思路。首先取出这人的最小投资月份,即2015-12,然后求大于2015-12的所有月份,即2016-02和2016-03,然后对2016-02和2016-03取最小,即求出来了第二次投资所在的那个月—2016-02,然后将其作为条件,对该月所有的投资金额求和。详细SQL如下:
SELECT
SUM(INVESTAMOUNT) AS FIRST_MONTH_INVEST_MONEY,
INVESTAMOUNT AS FIRST_INVEST_MONEY,
INVESTOR AS INVSTOR
FROM
DW_ODS.ODS_HZCF_T_INVEST
WHERE
DATE_FORMAT(INVESTTIME, '%Y%m') = (
SELECT
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
)
FROM
DW_ODS.ODS_HZCF_T_INVEST
WHERE
DATE_FORMAT(INVESTTIME, '%Y%m') > (
SELECT
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
)
FROM
DW_ODS.ODS_HZCF_T_INVEST
WHERE
FLAG = '30007001002'
AND INVESTOR = 'fff4d7d1752f4950b088c5b550a82ac9'
)
AND FLAG = '30007001002'
AND INVESTOR = 'fff4d7d1752f4950b088c5b550a82ac9' #fff4d7d1752f4950b088c5b550a82ac9)
)
AND FLAG = '30007001002'
AND INVESTOR = 'fff4d7d1752f4950b088c5b550a82ac9';
。下面看一下求所有用户的二投金额。先按求一个人的二投金额的方式试试。SQL如下:
SELECT
SUM(INVESTAMOUNT) AS FIRST_MONTH_INVEST_MONEY,
INVESTAMOUNT AS FIRST_INVEST_MONEY,
INVESTOR AS INVSTOR,
FLAG AS FLG
FROM
DW_ODS.ODS_HZCF_T_INVEST
WHERE
(
INVESTOR,
DATE_FORMAT(INVESTTIME, '%Y%m'),
FLAG
) = (
SELECT
INVESTOR AS MININVEST,
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
) AS MINTIME,
FLAG AS MINFLG
FROM
DW_ODS.ODS_HZCF_T_INVEST
WHERE
DATE_FORMAT(INVESTTIME, '%Y%m') > (
SELECT
INVESTOR AS MININVESTOR,
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
) AS MINTIME,
FLAG AS MINFLAG
FROM
DW_ODS.ODS_HZCF_T_INVEST
GROUP BY
MININVESTOR
HAVING
MINFLAG = '30007001002'
)
GROUP BY
MININVEST
HAVING
MINFLG = '30007001002'
)
GROUP BY
INVSTOR
HAVING
FLG = '30007001002';
显然,这样写会出很多问题。那么该怎么写呐?下面讲两种方法来实现上述需求。
1、子查询+临时表
SQL如下:
DROP TABLE TEM_1;
#求所有人首次投资的月份
CREATE TEMPORARY TABLE TEM_1 SELECT
INVESTOR AS MININVESTOR,
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
) AS MINTIME,
FLAG AS MINFLAG
FROM
DW_ODS.ODS_HZCF_T_INVEST
GROUP BY
MININVESTOR
HAVING
MINFLAG = '30007001002';
DROP TABLE TEM_2;
#求所有人二投所在的月份
CREATE TEMPORARY TABLE TEM_2 SELECT
INVESTOR AS MININVESTOR,
MIN(
DATE_FORMAT(INVESTTIME, '%Y%m')
) AS MINTIME,
FLAG AS MINFLAG
FROM
DW_ODS.ODS_HZCF_T_INVEST AS B
WHERE
DATE_FORMAT(INVESTTIME, '%Y%m') > (
SELECT
A.MINTIME AS MINTIM
FROM
(
SELECT
MININVESTOR AS MININVEST,
MINTIME
FROM
TEM_1
) AS A
WHERE
A.MININVEST = B.INVESTOR
)
GROUP BY
INVESTOR
HAVING
FLAG = '30007001002';
#求所有人的二投
SELECT
INVESTOR,
SUM(INVESTAMOUNT)
FROM
DW_ODS.ODS_HZCF_T_INVEST AS C
JOIN TEM_2 AS B ON C.INVESTOR = B.MININVESTOR
AND DATE_FORMAT(C.INVESTTIME, '%Y%m') = B.MINTIME
AND C.FLAG = '30007001002'
GROUP BY
C.INVESTOR;
2、嵌套查询+临时表
SQL如下:
DROP TABLE TEM_3;
#查询出所有人二投所在的月份,放入临时表-TEM_3
CREATE TEMPORARY TABLE TEM_3 SELECT
INVEST AS INVET,
MIN(
DATE_FORMAT(INVSTTIM, '%Y%m')
) AS MININVETIM,
FLG
FROM
(
SELECT
A.INVESTTIME AS INVSTTIM,
A.INVESTOR AS INVEST,
A.FLAG AS FLG
FROM
DW_ODS.ODS_HZCF_T_INVEST AS A,
(
#查询出所有人首次投资所在的月份
SELECT
INVESTOR,
DATE_FORMAT(MIN(INVESTTIME), '%Y%m') AS MINMONTH,
FLAG
FROM
DW_ODS.ODS_HZCF_T_INVEST
GROUP BY
INVESTOR
HAVING
FLAG = '30007001002'
) AS B
WHERE
A.INVESTOR = B.INVESTOR
AND DATE_FORMAT(A.INVESTTIME, '%Y%m') > B.MINMONTH
) AS C
GROUP BY
INVEST
HAVING FLG = '30007001002';
#用TEM_3中的投资时间作为连接D表和E表的一个条件,算出所有人的二投
SELECT
INVESTOR,
SUM(INVESTAMOUNT)
FROM
DW_ODS.ODS_HZCF_T_INVEST AS D
JOIN TEM_3 AS E ON D.INVESTOR = E.INVET
AND DATE_FORMAT(D.INVESTTIME, '%Y%m') = E.MININVETIM
AND D.FLAG = '30007001002'
GROUP BY
INVESTOR;
结语:经测试,第一种方法的效率更高些。表里共有8000多条数据,第一种方法耗时7秒多,第二种方法耗时9秒多。因此,推荐使用第一种方法,即用临时表。