SQL服务器:3个月的分区怎么办?
SQL Server: how to do 3 months' partition?
我想统计0-3个月分区的行数。月份由 MYMONTH 指定,格式为 201601
表示 2016 年 1 月。我正在使用 SQL Server 2014。如何在 3 个月内完成分区?
SELECT COUNT(*),
COUNT(*)
/
(COUNT(*) OVER (PARTITION
BY MYMONTH RANGE BETWEEN 3 MONTH PRECEDING AND CURRENT MONTH))
FROM myData
示例
| Month | Value | ID |
-------------------------|
| 201601 | 1 | X |
| 201601 | 1 | Y |
| 201601 | 1 | Y |
| 201602 | 1 | Z |
| 201603 | 1 | A |
| 201604 | 1 | B |
| 201605 | 1 | C |
| 201607 | 1 | E |
| 201607 | 10 | EE |
| 201607 | 100 | EEE|
计数
| Month | Count | Count3M | Count/Count3M |
-------------------------------------------
| 201601| 3 | 3 | 3/3 |
| 201602| 1 | 4 | 1/4 |
| 201603| 1 | 5 | 1/5 |
| 201604| 1 | 6 | 1/6 |
| 201605| 1 | 4 | 1/4 |
| 201607| 3 | 5 | 3/5 |
如果要统计前三个月的行数,使用条件聚合即可。您确实需要一种枚举月份的方法:
SELECT COUNT(*),
SUM(CASE WHEN yyyymm_counter <= 3 THEN 1 ELSE 0 END)
FROM (SELECT md.*,
DENSE_RANK() OVER (ORDER BY MYMONTH DESC) as yyyymm_counter
FROM myData md
) md;
没有子查询的另一种方法是将月份值转换为实际日期。让我假设它是一个字符串:
SELECT COUNT(*),
SUM( CASE WHEN DATEDIFF(month, CAST(MYMONTH + '01' as DATE), GETDATE()) <= 3
THEN 1 ELSE 0
END)
FROM MyData;
我在答案中遗漏了 /
。您需要注意 SQL 服务器进行整数除法,因此您可能得不到想要的结果——除非您将值转换为非整数(我建议乘以 1.0
或使用 1.0
而不是查询中的 1
。
您可以试试这个 (MSSQL 2012):
示例数据
CREATE TABLE mytable(
MONT INTEGER NOT NULL
,Value INTEGER NOT NULL
,ID VARCHAR(5) NOT NULL
);
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'X');
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'Y');
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'Y');
INSERT INTO mytable(MONT,Value,ID) VALUES (201602,1,'Z');
INSERT INTO mytable(MONT,Value,ID) VALUES (201603,1,'A');
INSERT INTO mytable(MONT,Value,ID) VALUES (201604,1,'B');
INSERT INTO mytable(MONT,Value,ID) VALUES (201605,1,'C');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,1,'E');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,10,'EE');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,100,'EEE');
查询 1
SELECT MONT, RC, RC+ LAG(RC,3,0) OVER ( ORDER BY MONT)+ LAG(RC,2,0) OVER ( ORDER BY MONT) + LAG(RC,1,0) OVER ( ORDER BY MONT) AS RC_3M_PREC -- + COALESCE( LEAD(RC) OVER ( ORDER BY MONT),0) AS RC_3M
FROM (SELECT MONT
, COUNT(*) RC
FROM mytable
GROUP BY MONT
) A
输出:
MONT RC RC_3M_PREC
----------- ----------- -----------
201601 3 3
201602 1 4
201603 1 5
201604 1 6
201605 1 4
201607 3 6
或使用您建议的内容(选项 ROWS ... PRECEDING):
查询 2:
SELECT MONT, RC
, COALESCE(SUM(RC) OVER (ORDER BY MONT ROWS BETWEEN 3 PRECEDING AND CURRENT ROW),0) AS RC_3M
FROM (SELECT MONT
, COUNT(*) RC
FROM mytable
GROUP BY MONT
) A
输出:
MONT RC RC_3M
----------- ----------- -----------
201601 3 3
201602 1 4
201603 1 5
201604 1 6
201605 1 4
201607 3 6
我想统计0-3个月分区的行数。月份由 MYMONTH 指定,格式为 201601
表示 2016 年 1 月。我正在使用 SQL Server 2014。如何在 3 个月内完成分区?
SELECT COUNT(*),
COUNT(*)
/
(COUNT(*) OVER (PARTITION
BY MYMONTH RANGE BETWEEN 3 MONTH PRECEDING AND CURRENT MONTH))
FROM myData
示例
| Month | Value | ID |
-------------------------|
| 201601 | 1 | X |
| 201601 | 1 | Y |
| 201601 | 1 | Y |
| 201602 | 1 | Z |
| 201603 | 1 | A |
| 201604 | 1 | B |
| 201605 | 1 | C |
| 201607 | 1 | E |
| 201607 | 10 | EE |
| 201607 | 100 | EEE|
计数
| Month | Count | Count3M | Count/Count3M |
-------------------------------------------
| 201601| 3 | 3 | 3/3 |
| 201602| 1 | 4 | 1/4 |
| 201603| 1 | 5 | 1/5 |
| 201604| 1 | 6 | 1/6 |
| 201605| 1 | 4 | 1/4 |
| 201607| 3 | 5 | 3/5 |
如果要统计前三个月的行数,使用条件聚合即可。您确实需要一种枚举月份的方法:
SELECT COUNT(*),
SUM(CASE WHEN yyyymm_counter <= 3 THEN 1 ELSE 0 END)
FROM (SELECT md.*,
DENSE_RANK() OVER (ORDER BY MYMONTH DESC) as yyyymm_counter
FROM myData md
) md;
没有子查询的另一种方法是将月份值转换为实际日期。让我假设它是一个字符串:
SELECT COUNT(*),
SUM( CASE WHEN DATEDIFF(month, CAST(MYMONTH + '01' as DATE), GETDATE()) <= 3
THEN 1 ELSE 0
END)
FROM MyData;
我在答案中遗漏了 /
。您需要注意 SQL 服务器进行整数除法,因此您可能得不到想要的结果——除非您将值转换为非整数(我建议乘以 1.0
或使用 1.0
而不是查询中的 1
。
您可以试试这个 (MSSQL 2012):
示例数据
CREATE TABLE mytable(
MONT INTEGER NOT NULL
,Value INTEGER NOT NULL
,ID VARCHAR(5) NOT NULL
);
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'X');
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'Y');
INSERT INTO mytable(MONT,Value,ID) VALUES (201601,1,'Y');
INSERT INTO mytable(MONT,Value,ID) VALUES (201602,1,'Z');
INSERT INTO mytable(MONT,Value,ID) VALUES (201603,1,'A');
INSERT INTO mytable(MONT,Value,ID) VALUES (201604,1,'B');
INSERT INTO mytable(MONT,Value,ID) VALUES (201605,1,'C');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,1,'E');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,10,'EE');
INSERT INTO mytable(MONT,Value,ID) VALUES (201607,100,'EEE');
查询 1
SELECT MONT, RC, RC+ LAG(RC,3,0) OVER ( ORDER BY MONT)+ LAG(RC,2,0) OVER ( ORDER BY MONT) + LAG(RC,1,0) OVER ( ORDER BY MONT) AS RC_3M_PREC -- + COALESCE( LEAD(RC) OVER ( ORDER BY MONT),0) AS RC_3M
FROM (SELECT MONT
, COUNT(*) RC
FROM mytable
GROUP BY MONT
) A
输出:
MONT RC RC_3M_PREC
----------- ----------- -----------
201601 3 3
201602 1 4
201603 1 5
201604 1 6
201605 1 4
201607 3 6
或使用您建议的内容(选项 ROWS ... PRECEDING):
查询 2:
SELECT MONT, RC
, COALESCE(SUM(RC) OVER (ORDER BY MONT ROWS BETWEEN 3 PRECEDING AND CURRENT ROW),0) AS RC_3M
FROM (SELECT MONT
, COUNT(*) RC
FROM mytable
GROUP BY MONT
) A
输出:
MONT RC RC_3M
----------- ----------- -----------
201601 3 3
201602 1 4
201603 1 5
201604 1 6
201605 1 4
201607 3 6