SqlServer开窗函数


 https://www.bilibili.com/video/BV1k44y1Y73j?p=1&vd_source=4c907fba67f1d94da623c068af8ed9d8

一、什么是窗口函数(开窗函数)

简单来说,对数据结果集不破坏原来的,进行聚合、排名、统计分析操作。支持数据库,Mysql8.0Mssqlerver 2012oracle 10g

基本语法:OVER ( [ partition_by_clause ] order_by_clause ),详细语法如下:

OVER (

       [ ]

       [ ]

       [ ]

      ) 

::=

PARTITION BY value_expression , ... [ n ]

::=

ORDER BY order_by_expression

    [ COLLATE collation_name ]

    [ ASC | DESC ]

    [ ,...n ]

::=

{ ROWS | RANGE }

::=

{   

  |

}

::=

  BETWEEN AND

::=

{   

  |

}

::=

{

    UNBOUNDED PRECEDING

  | PRECEDING

  | CURRENT ROW

}

::=

{

    UNBOUNDED FOLLOWING

  | FOLLOWING

  | CURRENT ROW

}

::=

{   }

二、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="  指定至少包含 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://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2012/ms189461(v=sql.110)?redirectedfrom=MSDN

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,leadmsssql2012才能支持

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