SqlServer开窗函数
https://www.bilibili.com/video/BV1k44y1Y73j?p=1&vd_source=4c907fba67f1d94da623c068af8ed9d8
一、什么是窗口函数(开窗函数)
简单来说,对数据结果集不破坏原来的,进行聚合、排名、统计分析操作。支持数据库,Mysql8.0,Mssqlerver 2012,oracle 10g
基本语法:OVER ( [ partition_by_clause ] order_by_clause ),详细语法如下:
OVER (
[ <PARTITION BY clause> ]
[ <ORDER BY clause> ]
[ <ROW or RANGE clause> ]
)
<PARTITION BY clause> ::=
PARTITION BY value_expression , ... [ n ]
<ORDER BY clause> ::=
ORDER BY order_by_expression
[ COLLATE collation_name ]
[ ASC | DESC ]
[ ,...n ]
<ROW or RANGE clause> ::=
{ ROWS | RANGE } <window frame extent>
<window frame extent> ::=
{ <window frame preceding>
| <window frame between>
}
<window frame between> ::=
BETWEEN <window frame bound> AND <window frame bound>
<window frame bound> ::=
{ <window frame preceding>
| <window frame following>
}
<window frame preceding> ::=
{
UNBOUNDED PRECEDING
| <unsigned_value_specification> PRECEDING
| CURRENT ROW
}
<window frame following> ::=
{
UNBOUNDED FOLLOWING
| <unsigned_value_specification> FOLLOWING
| CURRENT ROW
}
<unsigned value specification> ::=
{ <unsigned integer literal> }
二、docker 安装sql server 2019
https://www.jianshu.com/p/70baab8006c3
docker pull mcr.microsoft.com/mssql/server:2019-latest
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=SA@12345" -p 1435:1433 --name sql-server2019 -h sql-server2019 -d mcr.microsoft.com/mssql/server:2019-latest
说明:
-e "ACCEPT_EULA=Y" 将 ACCEPT_EULA 变量设置为任意值,以确认接受 最终用户许可协议。 SQL Server 映像的必需设置。
-e "SA_PASSWORD=<YourStrong@Passw0rd>" 指定至少包含 8 个字符且符合 SQL Server 密码要求的强密码。 SQL Server 映像的必需设置。 默认情况下,密码的长度必须至少为 8 个字符,并且必须包含以下四种字符中的三种:大写字母、小写字母、十进制数字和符号
-p 1435:1433 将主机环境中的 TCP 端口(第一个值)映射到容器中的 TCP 端口(第二个值)
注意端口:127.0.0.1,1435
中文乱码问题:https://blog.csdn.net/xingkongtianyuzhao/article/details/103944280
改一下表结构:中文字段加上,COLLATE Chinese_PRC_CI_AS解决
三、实操
参考文档:
https://www.cnblogs.com/longling2344/p/5704384.html
https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2012/hh231256(v=sql.110)
基本实践:
Select count(ipt_no) from ip_rec
Select count(ipt_no),t.* over() from ip_rec
SELECT t.*,COUNT (t.ipt_no) OVER (PARTITION BY t.adm_dept_codg) 按科室计算人次 FROM
ip_rec t order by t.adm_dept_codg,t.ipt_no;
SELECT t.*,COUNT (ipt_no) OVER (PARTITION BY t.adm_dept_codg,t.doctor_codg) 按科室和医生计算人数 FROM ip_rec t
order by t.adm_dept_codg,t.doctor_codg,t.ipt_no;
PARTITION BY作用相当于group by
select t.adm_dept_name,count(t.ipt_no) from ip_rec t group by t.adm_dept_name
实操案例:
需求1:需要统计24小时之内出入院的患者信息
注意:lag,lead要msssql2012才能支持
SELECT
pkid,
ipt_no,
pat_name,
pat_sex,
adm_date,
dscg_date,
lag(t.dscg_date,1) OVER (PARTITION BY t.ipt_no order by t.adm_date) 上一次出院日期,
lead(t.dscg_date,1) OVER (PARTITION BY t.ipt_no order by t.adm_date) 下一次入院日期,
adm_dept_codg,
adm_dept_name,
dscg_dept_codg,
dscg_dept_name,
doctor_codg,
doctor_name
FROM
ip_rec t
ORDER BY
t.ipt_no,
t.adm_date
需求2:统计患者住院次数
SELECT
rank() OVER (PARTITION BY t.ipt_no order by t.adm_date) 住院次数,
t.*
FROM
ip_rec t
ORDER BY
t.ipt_no,
t.adm_date
需求3:某个患者多次住院费用累加
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW 意味着该函数对其操作的行的窗口在大小上是 3 行、以当前行之前(包括当前行)的 2 行开头。
SELECT
pkid,
ipt_no,
pat_name,
pat_sex,
adm_date,
dscg_date,
t.fee,
SUM (fee) OVER (
PARTITION BY t.ipt_no
ORDER BY t.adm_date
ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW
) 累加金额,
adm_dept_codg,
adm_dept_name,
dscg_dept_codg,
dscg_dept_name,
doctor_codg,
doctor_name
FROM
ip_rec t
ORDER BY
t.ipt_no,
t.pat_name
综合案例实操:
SELECT
pkid,
ipt_no,
pat_name,
pat_sex,
adm_date,
dscg_date,
t.fee,
SUM (fee) OVER (
PARTITION BY t.ipt_no
ORDER BY t.adm_date
ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW
) 累加金额,
SUM (fee) OVER (
PARTITION BY t.ipt_no
ORDER BY t.adm_date
ROWS BETWEEN 1 PRECEDING and 1 FOLLOWING
) 相邻三条数据累加,
lag(t.dscg_date,1) OVER (PARTITION BY t.ipt_no order by t.adm_date) 上一次出院日期,
lead(t.dscg_date,1) OVER (PARTITION BY t.ipt_no order by t.adm_date) 下一次入院日期,
adm_dept_codg,
adm_dept_name,
dscg_dept_codg,
dscg_dept_name,
doctor_codg,
doctor_name
FROM
ip_rec t
ORDER BY
t.ipt_no,
t.pat_name