窗口函数之虚拟数字辅助表


数字辅助表是一个整数序列,可以用它来完成多种不同的查询任务。数字表有很多任务,如生成日期和时间值序列,及分裂值列表。通常,建议在数据库中保存这样一个永久表,并填充尽可能多的数字,然后需要的时候查询它,然而,在某些环境中,我们没有机会创建和填充新的表,以及需要的查询逻辑。

下面函数摘自 T-SQL性能调优秘笈——基于SQLServer2012窗口函数

创建虚拟数字辅助函数


use master --根据实际需要修改要保存的库中
go
--判断是否已存在 创建函数名、如果存在则执行删除操作
if OBJECT_ID('dbo.GetNums','IF') is not null drop function dbo.GetNums
go
--创建函数 GetNums 并指定 两个参数及返回值类型 这里以table 的形式返回
create function dbo.GetNums(@low as bigint ,@high as bigint) returns table
as
--函数体
return
with
--新建L0 内容中添加2行
L0 as(select C from(values(1),(1)) as D(c)),
--新建L1 数据来源L0 并连接L0 得到4行数据,L1的数据量为L0的 二次方
L1 as(select 1 as C from L0 cross join L0 as B),
L2 as(select 1 as C from L1 cross join L1 as B),
L3 as(select 1 as C from L2 cross join L2 as B),
L4 as(select 1 as C from L3 cross join L3 as B),
--至此 L5的数据达到了 2^2^2^2^2 数据量达到 4,294,967,296 行数据
L5 as(select 1 as C from L4 cross join L4 as B),
--将L5数据排序 使用带 order by (select null) 的row_number() 生成实际的数字
Nums as (select row_number() over(order by (select null)) as rownum from L5) --根据 参数@low,@high 限定实际的输出行数。
/** SQLServer 2012 后的写法,SQLServer 2012 添加了 offset /fetch 选项 **/
select @low+rownum -1 as n from Nums order by rownum
offset 0 rows fetch first @high - @low +1 rows only; /** SQLServer 2012 以前**/
--select top(@high -@low +1) @low+rownum -1 as n from Nums order by rownums;
go

测试函数生成效果

  1. 获取范围在11-50 列
select n from dbo.GetNums(11,50)
  1. 性能测试 获取0-1000000内列
select n from dbo.GetNums(0,1000000) --执行时间在10S左右
  1. 生成日期序列
--设定参数 起始时间 和结束时间
--请自行查阅 SQLServer中 日期函数
declare
@start as date = '20210701',
@end as date ='20210901'
--得到 每天 日期序列
select dateadd(day,n,@start) as date from dbo.GetNums(0,datediff(day,@start,@end))
--得到没12小时 时间间隔的日期序列
select dateadd(HOUR,n*12,@start) as date from dbo.GetNums(0,datediff(HOUR,@start,@end)/12)
--通过修改 date 函数中时间得到不同时间间隔时间序列,比如,年,月,周,天,时,分,秒

生成样本数据

使用虚拟数字辅助表 实现生成样本数据,以供测试使用

新建两张数据表用来模拟 存储银行的账户信息、和交易流水

  1. 创建表表结构
if OBJECT_ID('dbo.transactions','U') is not null drop table transactions;
if OBJECT_ID('dbo.accounts','U') is not null drop table accounts; create table dbo.accounts(
actid int not null, --用户id
actname varchar(50) not null, --用户名
constraint pk_accounts primary key(actid)
);
create table dbo.transactions(
actid int not null, --用户id
tranid int not null, --消费流水号
val money not null, --消费值
trandate datetime not null, --日期
constraint pk_transactions primary key(actid,tranid),
constraint fk_transactions_accounts
foreign key(actid)
references dbo.accounts(actid)
);

根据虚拟数字辅助函数,生成样本数据、并添加到数据表中

在accounts 中添加100个账户,并在transactions 表中为每个账户生成 20000笔交易

  1. 添加账户信息

--添加100个用户账户,并将名称 命名为 account+序列号
insert into dbo.accounts with(tablock)(actid,actname)
select n as actid,'account'+cast(n as varchar(10)) as actname
from dbo.GetNums(1,100)

  1. 添加消费流水记录
--为每个账号添加20000个交易记录,由于交易时间不是固定的这里使用随机数 rand()进行日期拼接
insert into dbo.transactions with(tablock)(actid,tranid,val,trandate)
select a.n as actid,t.n as tranid,
(abs(CHECKSUM(newid())%2)*2-1)*(abs(CHECKSUM(newid())%1300)) as val, --随机消费值
--由于消费记录不一定在固定的时间点,这里用的随机生成日期形式。
convert(datetime,
datediff(day,'1900-01-01','2010-01-01') --计算 1900-01-01 到 开始日期
+ abs(CHECKSUM(newid()))%datediff(day,'2010-01-01','2021-09-01') --开始时间到随机结束时间的随机数
+(abs(CHECKSUM(newid())%86400000)*0.00000001)) --生成时分秒时间 86400000为每天的固定毫秒数
as trandate
from dbo.GetNums(1,100) as a
cross join dbo.GetNums(1,20000) as t

这里的随机数尝试用 rand()方法 生成时间日期整张表相同,随之弃用,也尝试封装过值函数 newid() 关键字 显示报错 在函数内对带副作用的运算符 'newid' 的使用无效。 然后才想到这种办法

核实表数据,发现好多数据不合常理,比如:消费流水号 tranid 与 日期不符,

--修改数据让数据更合理 利用窗口函数排序进行修改参数
with g as(
select actid,tranid,val,trandate,
ROW_NUMBER() over(partition by actid order by trandate) as rownum
from transactions
)
update g set g.tranid=rownum

修改完成后 数据看起来还比较合理 有一个地方需要注意 消费流水号 前几行相加出现负数的情况,可以通过修改流水号,让数据看起来是某一短时间值,比如:在流水号 加一个固定的值,或者在添加数据时 修改 GetNums() 中的参数 例如:cross join dbo.GetNums(500000,520000) as t 这样就比较合理了

下篇文章介绍SQLServer 的几个窗口函数,数据基于 添加样本数据表transactions

虚拟数字存储表——SQLServer2012可高用的更多相关文章

  1. SQL Server 怎样生成序列号(虚拟数字辅助表)

    </pre><pre name="code" class="sql">--生成一个"序列" 或者说生成一个" ...

  2. SQL虚拟数字辅助表

    虚拟数字辅助表是一个整数序列,可以用来完成多种不同的任务,如生成日期跟时间值序列,及分裂值列表.要用查询逻辑产生一个大的整数序列,可以使用交叉连接(cross join). 交叉联接(cross jo ...

  3. 使用Spark加载数据到SQL Server列存储表

    原文地址https://devblogs.microsoft.com/azure-sql/partitioning-on-spark-fast-loading-clustered-columnstor ...

  4. 乘风破浪,遇见未来元宇宙(Metaverse)之进入元宇宙世界,虚拟数字人行业洞察报告

    正值元宇宙热潮,虚拟数字人兴起 作为⼀个新兴领域,虚拟数字⼈已经引起市场和资本的⾼度关注,截⾄目前据不完全统计,全球范围已有500+虚拟数字人相关项目获得融资,融资总额超10亿美元,并且融资项目和总额 ...

  5. SQL Server数字辅助表的实现

        数字辅助表是一个连续整数的数列,通常用来实现多种不同的查询任务.大多分两类:足够大物理数字表和表函数,前者可以称为静态的,后者可以称为动态且按需生产. 物理数字表     物理数字表通常存在一 ...

  6. 含有虚拟列的表 怎么用EXP导出?

    最近导一个测试库,报有虚拟列的表不支持,如下: EXP-00107: Feature (VIRTUAL COLUMN) of column CTB_CLIENT_SUBMIT_TIME_MONTH i ...

  7. Greenplum table 之 appendonly的列存储表

    一.appendonly的列存储表 1.创建列存储表 create table test_column_ao( id bigint, name varchar(128), value varchar( ...

  8. 窗口函数至排序——SQLServer2012可高用

    常用到的窗口函数 工作中要常对数据进行分析,分析前要对原始数据中找到想要的格式,数据原本存储的格式不一定时我们想要的,要在基础上进行一定的处理,下面介绍的几种方式是常用的数据排序的集中方式,包含 排名 ...

  9. 20170707xlVBA多区域拆分多表保持行高列宽

    Public Sub 多个区域拆分到多表() AppSettings On Error GoTo ErrHandler Dim StartTime, UsedTime As Variant Start ...

随机推荐

  1. PhotoShop CC2015(64位)下载链接和破解教程

    photoshop如今有cc和cs两种版本,之前出了一个cs的破解教程和扣圆形图,有很多朋友说cc比cs好用的多,希望出个cc的下载链接和破解教程,故推出2015pscc版破解教程和下载链接. 百度云 ...

  2. 深度掌握 Java Stream 流操作,让你的代码高出一个逼格!

    概念 Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选.排序.聚合等. Stream 的操作符大体上分为两种:中间操作符和终止操作符 中 ...

  3. C++利用模板在Windows上快速调用DLL函数

    更新日志 --------- 2021/08/01 更新V2.2 增加 GetHmodule 函数 - 允许用户获取HMODULE以验证加载DLL是否成功. 2021/08/03 更新V2.3 增加 ...

  4. 记一次WindowsServer2012提权 - 烂土豆

    此次主题:烂土豆 shell咋拿的 我也忘了 好像是添加友情链接那里还是啥 不重要了 直接获取shell后 先用systeminfo > 1.txt了一下 然后放到了 windows-explo ...

  5. 三年Android开发快手、美团、支付宝连挂,怒刷1549页面试题字节上岸

    刚开始面试的时候我真的是处处碰壁,面一家挂一家,面完之后怀疑自我,是不是自己真的太菜了找不到工作.工作本身就是双向选择,一家不行再换一家,总有合适的,千万不要因为别人的一句话就全盘否定自己,一定要自信 ...

  6. 【Android面试查漏补缺】之事件分发机制详解

    前言 查漏补缺,查漏补缺,你不知道哪里漏了,怎么补缺呢?本文属于[Android面试查漏补缺]系列文章第一篇,持续更新中,感兴趣的朋友可以[关注+收藏]哦~ 本系列文章是对自己的前段时间面试经历的总结 ...

  7. 跟我一起写 Makefile(九)

    使用函数 ---- 在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能.make所支持的函数也不算很多,不过已经足够我们的操作了.函数调用后,函数的返回值可以当做 ...

  8. 用SamInside破解Windows登录密码

    用小马PE的USB-HDD+格式制作启动优盘: 笔记本启动时按ESC键,选择USB启动: 进入WinPE后,将%SystemRoot%/system32/config全部拷贝出来(WinXP这个文件夹 ...

  9. VIM正则表达式的懒惰模式

    例如有如下一段话: Another whale sighting occurred on , <2004>. AK and HI 要匹配每一个<...>,如果用<.> ...

  10. Linux 基础学习篇 序篇

    读序篇可以知道的: 1.有些指令知道前和知道后,自己的操作是完全不同的,可能知道前,会用reset把系统重新启动一遍,而知道后会使用ps和kill来关闭进程. 2.如果对Linus的学习知识" ...