作者:cooperyjli,腾讯 CDG 数据分析师

SQL的全称是Structured Query Language(结构化查询语言),是一种古老而简洁的程序设计语言。看似平平无奇,一直被各种吐槽,但却有着众多语言所难得的漫长寿命,并展现出极好的拓展性,在不同时期衍生出不同的子语言。笔者作为腾讯TDW体系下的SQL现役运动员,对日常工作中常用的基础知识和展开的业务实践予以了总结,可供读者参考。

结构化查询语言,顾名思义,它的基础在于结构化的数据库表,最主要的应用场景在于数据查询,虽然SQL也可以像其它语言一样有一些高级的写法,但它的主战场并不在此,仍要回归到对数据库表的操作和处理中。以下分为基础知识篇和业务实践篇展开介绍,其中基础知识篇盘点了一些常用的技能点,业务实践篇则总结了几点日常工作里的思考。

第一部分 基础知识篇

围绕着数据库表,可以展开许多的主题工作,有些是比较专业性的领域,如事务处理和权限管控等,这些更多是面向底层的技术基础,部分属于DBA的工作范畴。对于使用SQL的很大部分用户群体来说,则集中于对数据库表的增删查改,聚合汇总里,这些是面向业务的数据工作。针对这一块的内容,继续将其细分到不同的子场景里,逐一展开介绍。

1.库表基本操作

库表预览: SQL最基础和最核心的两个对象,便是数据库和数据表,基于一个业务场景,可以有N个数据库,在一个数据库里面,又可以有N张数据表。数据库的连接与切换,数据表的创建与删除,是使用SQL进行库表预览的基本操作。 这些基本操作,可以通过前端的可视化界面进行,也可以从后台直连数据库展开,需由使用者所拥有的权限级别来选择。

数据增删: 除了一些常规的每日运行的计算任务外,很多时候我们只是单纯地想对一张表进行处理,比如插入几条数据,更新某个字段值,或者剔除几条数据。这些操作往往是单次的,局部的,目的清晰,所以掌握几个关键字就可以实现,如INSERT/UPDATE/DELETE等。

视图应用: 视图的引入,相当于在统计逻辑和实际库表之间提供了一种折中的方案。完成这个功能,逻辑上是必须有这么几道工序的,但又不想在每一道工序里都落地一张实际的数据表,显得繁琐而臃肿,那就引入视图吧,把这些中间的工序用视图的形式去实现和替代

关键字: 其实SQL真的是一门很简洁的语言,市面上也不会有大本的书籍专门讲述SQL的书写方式,因为相对于其它语言来说,SQL归根到底,只是围绕着几个关键字的一些基础语句而已。只要把这几个关键字掌握了,SQL的大部分内容其实就已经展开了。

2.数据查询语句

SQL作为面向数据库表的基础语言,用户群体具有多样性,从技术底层往业务层走,往往会有DBA,数据开发,数据分析,产品经理等这些用户角色。不同用户群体对SQL的侧重点是有差异的,但无论是哪一个群体,基本都绕不开数据查询语句,是一块必要内容。

简单查询: 能写一个简单查询语句,其实就已展开了和数据库表的对话过程。不管是哪种SQL的拓展语言,简单查询里的语法基本都还是一致的。比如用*代表全量查询,用distinct去重,用top和limit对数据条数做基本限制,以及用as对原表字段名进行替换更新等。

过滤查询:在简单查询的基础上,添加一些约束条件,也就是过滤查询。比如你可以用关键字where查看其中某天的数据,用between或者in来限制一个范围,用like或者relike来做正则匹配,也可以用and或者or这两个通配符对这些约束条件进行排列组合。

排序查询: 排序查询可以细分为两个场景,一个是在查询内部的排序,即根据某个字段的属性值进行表内部分区,对分区进行排序查询后输出,可以用row_number的形式来实现;另一个是把整个查询当做一个整体,对结果表进行排序查询后输出,用order by来实现即可。

3.数据聚合与连接

前面讲数据查询语句,不管怎么查询,其实并不影响原生的表结构,即原来的表是按照什么逻辑写的数据,查询结果里的数据也是基于这种逻辑,只是筛选了局部数据而已。但数据聚合与连接就不一样了,聚合会在纵向上改变原生表结构,连接则在横向上拓展了表结构。

数据聚合: 要对一张表做数据聚合,其实理解了两个概念即可,维度和指标。维度是你要基于哪些字段来做聚合,指标是在这个维度之上,你想用什么汇总函数生成哪些指标。数据聚合的关键字是group by,维度里的属性值仍来自于原生表,指标则是新生成的汇总值。

数据连接: 对两张表或者N张表做连接,是SQL里面非常重要的一个内容,也是最容易埋坑的一个坑点。尽管数据连接只涉及四种方式,七个语法,但其仍然是绝大部分SQL脚本的核心内容。选择合适的可靠的数据连接方式,应该是一个SQL运动员的基本功了。


4.函数应用

函数库,其实就像是一个数据处理与分析的百宝箱,收藏着各种场景下需要用到的车轮子。对函数库的熟悉和掌握,可以较好地提升工作效率,也让计算脚本显得轻量而简洁。毕竟站在通用的函数的肩膀上,很多统计逻辑是可以一步到位的,不需要沉迷于山重水复的自主构造里。以下参考TDW的函数库分类,将日常所用的函数细分为几个子类别。

4.1数学函数: SQL里的数学函数主要和数值处理有关,有取值函数和变换函数等。取值函数包括round四舍五入,abs取绝对值,ceil向上取整等,主要用于对具体数值的细节调整;变换函数则会改变该字段的数据分布形态,如正弦sin,余弦cos,或者开根号sqrt等。

4.2聚合函数: 在数据聚合中,选择了具体字段作为聚合维度后,之后便是应用各种聚合函数得到汇总值的过程。其中有简单聚合函数如count计数,sum求和,avg求平均,也可以基于分布特征,max/min取极值,std取标准差,variance取方差,另外若在聚合过程中涉及分区处理的话,也有rank,first/last_value,row_number等函数可以应用。

4.3时间和日期函数: 对时间数据的处理,同样也是SQL里的一个重要课题,主要细分为时间的加减,取值和转换这么三类。其中时间加减里,又涉及不同的时间维度,比如按日维度有date_diff,date_add,date_sub等,按月维度有month_between,add_months等。时间取值函数则是在一个详细的时间戳里,取出自己想要的部分,如year,month,day,hour等。时间转换函数则是时间形式的切换,如日期格式,格林尼治时间戳格式等。

4.4文本处理: 数据类型可以粗糙地分为数值数据和文本数据,对于文本数据的处理,也有很多对应的函数。其中有一些简单取值函数,如通过length和size获得字段长度和数组大小,通过upper和lower可以切换大小写;字符串的切割与拼接,由浅入深有split,substr,concat,wm_concat等;最后正则表达式也是文本处理中一个特别重要的模块。

4.5其它函数: 除了以上所盘点的一些通用函数外,其实在日常工作中会有很多垂直的业务场景,在这些特定场景下也有一些特定的函数逻辑。比如涉及数组结构拆分与重构时,可以应用later view函数;涉及字段编码时,也有加密与解析函数;除此之外,还有逻辑函数,转换函数等多种特殊函数,在特定的场景下,这些函数其实也是必要的。

5.具体开发环境的注意点

和其它众多语言一样,SQL的编写也不能脱离其自身的开发环境,不同的数据库形态,不同的IDE,都会有一些差异点和新特性。同样的一段脚本,在A环境下可能跑的疾速如飞,在B环境下却可能满屏报错,可以拿出来讨论的,往往只是一些通用的逻辑和思考。除此之外,具体开发环境里的注意事项,一些细节的加速点,则是要在具体环境里去发现和探索。

第二部分 业务实践篇

一种语言,一个函数库,就像是厨房里的各种厨具,它们可能或优良或劣质,但本质上还是一些标准化的组件。基于这些公共的组件,如何去烹制自己的美食,以及在烹制过程中的心得和思考,则属于业务实践的篇章。在业务实践的过程中,不管怎样去规范化,标准化,每个人输出的脚本内容,难免还是要带上私人的特质的,这同样也是一个需要修习的部分。

以下通过三个问题点,来引出笔者在实际工作中的一些反思。其中如何尽量地少给未来挖坑,介绍了一些反面的案例,这些反面的细节在积累之后,容易引起整个系统的不稳定性;如何健康地做数据规划,则是从一个创建者的身份,展开几点数据规划的思考;但不管做了多么缜密和丰富的准备,随着时间推移,总还是会出现变化的,所以在破旧与立新之间要找到平衡点。这些反思是基于工作实践的层面,难免会有幼稚和纰漏之处,还请读者轻拍。

1.如何尽量地少给未来挖坑

不要起一些奇奇怪怪的名字: SQL里的数据库表,就像是其它语言里的对象,往往是数量极大的,并在时间的推进,业务的发展中,基数会持续放大。所以对于数据库名,数据表名,字段名,尤其是一些主键,索引的命名,务必要有一套相对统一的规范。缺乏规范的约束时,你无法想象人的想象力会多么发散,这些奇奇怪怪的名字,最终会把人深深地困住的。

不要并行维护多个版本的数据: 因为业务的拓展,数据背后的口径可能有所变更,基于旧有的数据报表,简单修改后出一份新数据,是一种成本较低的实现方式。但最好不要并行维护多个版本的数据,当版本超过3个的时候,维护的成本是直线拉升的。所以当要做数据变更时,一方面可以降低变更的频率,另一方面尽量在原有报表里修改,并替换掉原有口径。

不要在单个脚本里写过多内容: 统计逻辑的实现,就像是传统工业里的不同工序,这个过程里存在两种极端。一种是把一个逻辑在横向/纵向细分为太多的工序,部署过多计算任务,形成很大冗余;另一种是完全打包在一个大脚本里,这种情况也不利于问题定位和中间数据处理。所以不要在单个脚本里写过多内容,可以将它拆分进最优数量的计算任务中。

要有一些基本的约束条件: 做一些事情时,不仅要立足于眼下的问题点,也要考虑一下未来可能发生的变化。就像是造一座桥,修一条路,总要考虑极限情况下的压力。很多的数据异常,往往是在业务变化时,旧有的逻辑不能适应当前的场景。所以在一开始写脚本时,要考虑一下未来的场景,有一些基本的约束条件,这样会让所部署的任务会有较好的稳定性。

要采用尽量简洁的写法: 能够一步到位的统计逻辑,就采用尽量简洁的写法,千万不要去绕圈子。尤其是一些核心脚本,是要在不同环节,不同阶段的同事之间传承的,很多人并不了解当时的业务背景和需求逻辑,如果写法太绕圈子的话,最终就把大家一起绕进去了。

2.如何健康地做数据规划

数据规划是一个层级比较中等的概念,往下一层,做需求开发时,往往只聚焦于特定的需求点,并不涉及其它内容;往上一层,做数据工程的话,又是基于整个部门,整个产品形态的框架搭建。但数据规划更多是应对一个相对独立的业务场景,所做的规划与设计。

一个不够好的数据规划,可能会引发后续的诸多问题点,比如:

痛点1: PM提出要在视图上扩展一个细分字段,觉得很简单。我也觉得很简单,但就是更改不了,因为这个字段在数据源处理中就舍弃了,无法从上一层数据表中获得。

痛点2: 想要重跑一个时间范围内的数据,但这张表不是分区表,无法并行处理;想要剔除某个日期内的数据,但不同表中时间格式不一致,导致处理结果有差漏等。

痛点3: 同样的一条统计链路,部分为了保障每日推送而独立出去,部分为了特性统计而独立出去,由此产生了众多的细分链路,此后的变更也要在不同链路之间同步处理。

以上列出的三个痛点,分别对应了原始信息的保留,技术实现的最优路径,以及计算任务的细分问题等,不过也只是数据规划需要思考的其中一部分问题点。在不同的业务场景下里,可以有不同的数据规划思路。粗糙地讲,可以分为数据基础层和业务细分层独立处理。

数据基础层: 做一个数据规划,首先应该要考虑数据本身,在数据基础层里,应暂时抛开具体的业务细节,以数据为重。这个时候应在处理中尽量地保留原始信息,同时要对数据源做好质量检验,第一道防线,往往是很重要的一道防线。原始信息要完整,数据质量要合格,任务部署要轻便,这些是数据基础层的一些目标,也是后续工作的一个前提。

业务细分层: 数据基础要独立而完整,面向数据本身;业务细分层则可以去细分实现,面向业务细节。基于不同的业务目标,可以从源表中筛选不同的内容,用于应对特定的场景。这样的数据+业务层级,形成了一种“总-分”结构,是数据规划的其中一种实现方式。

3.如何在破旧与立新之间寻找平衡点

很多的工作,都是基于当下的场景,即使做了详尽的规划和思考,也不可能应对未来的所有问题。当业务逐渐地深入发展时,很多的内容也需要做一些同步处理,小的层面上是一些数据表和视图的表更,大的层面上可能涉及计算平台的迁移,视图系统的重建等。

破旧与立新,往往是一个长期存在的问题点。不需要每天都进行自我“革命”,但改良和优化,则是一个长期过程。在这个长期过程里,我们需要在破旧与立新之间寻找到平衡点。

以上是笔者在TDW体系下写SQL的一些实践和思考,欢迎评论区留言讨论~

一文搞懂 SQL:基础知识和业务实践总结相关推荐

  1. 一文搞懂 DNS 基础知识,收藏起来有备无患~

    你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 juejin.cn/post/6844903497494855687 推荐:ht ...

  2. 一文搞懂IT基础知识,讲通HTTP、TCP、IP、以太网

    最近部门组织了一次前端性能优化交流会,大家从输入页面 URL 到最终页面展示内容这个过程提出了许多优化点.但同时发现很多同学对 HTTP 协议层的知识不能串联起来,于是整理了这篇文章,希望可以给大家带 ...

  3. 一文搞懂 DNS 基础知识,收藏起来有备无患

    点击上方 "编程技术圈"关注, 星标或置顶一起成长 后台回复"大礼包"有惊喜礼包! 每日英文 Life is just like a journey. Ther ...

  4. 一文搞懂数据库锁知识

    数据库锁知识(INNODB) 库锁 表锁 MDL锁 意向锁 在线DDL的效率问题 锁升降级机制 行锁 四种隔离级别 行锁的分类 行记录锁(Record Locks) 间隙锁(Gap Lock) 临键锁 ...

  5. 一文搞懂python3基础大全(变量,标准数据类型,标识符,行与缩进,运算符和表达式,条件语句if,循环语句,函数,文件,面向对象,错误和异常,模块)

    2.Python3基础 2.1.变量 Python 中的变量不需要声明.每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建.变量没有类型,"类型"是变量所指的内存中对象的类型 ...

  6. 一文搞懂SQL注入攻击

    SQL注入攻击 1. 前言 2. SQL注入简介 3. SQL注入步骤 4. 防范SQL注入 1. 前言 随着互联网的发展和普及,网络安全问题越来越突出,网络在为用户提供越来越多服务的同时,也要面对各 ...

  7. 一文看懂MOSFET基础知识

    什么是MOSFETMOSFET的原意是:MOS(Metal Oxide Semiconductor金属氧化物半导体),FET(Field Effect Transistor场效应晶体管),即以金属层( ...

  8. 一文搞懂SQL中的各种联结——内联结、自然联结、自联结、交叉联结

    一.概述 所谓" 联结 "指的是数据表和本身,以及不同数据表之间的" 联结关系 ".常见的联结有自连接.自然连接.内连接.外联结.完全连接等等.本文以SQLit ...

  9. 广告算法所需要搞懂的基础知识

    先简单解释下基本的:DSP(Demand Side Platform)是需求方平台,负责接受投放需求,找人群数据,实现投放竞价等功能的那么一个中央管理控制平台.DMP(Data Management ...

最新文章

  1. NOI2004 郁闷的出纳税——SBT应用
  2. Delphi下的COM编程
  3. thinkphp-条件判断-范围判断-NOTBETWEEN
  4. 判断101-200之间有多少个素数,并输出所有素数(C)
  5. 转-《高性能mysql》并不是一本好书——SQL笔记
  6. loewe测试软件,实测Loewe三角包 最轻的小包最贴心的设计
  7. iphone查看删除的短信_苹果删除的短信
  8. table表格表头不懂,内容y轴滚动
  9. 模型需要对特征进行归一化吗_模型融合完全手册 - 套娃的艺术:将模型作为特征进行建模...
  10. Application page and Site page
  11. 更改Xcode的缺省公司名(转)
  12. python输出文本和值_Python有没有函数打印当前对象的所有属性和值?_others_酷徒编程知识库...
  13. python的整数类型_python基本数据类型
  14. STM32串口中断接收
  15. java 网易邮箱_Java mail 163邮箱配置
  16. Centos8装Wine笔记
  17. Python中英文词频统计
  18. cv2.VideoWriter生成视频无法播放的原因(持续补充)
  19. 0.《JavaScript高级程序设计》(Nicholas C.Zakas 第3版)
  20. 独孤木专栏Delayed Project(中) (转)

热门文章

  1. 深入分析 Java 方法反射的实现原理
  2. java不带package和带package的编译方式
  3. jquery 实现返回顶部功能
  4. 【2D动画】《想你》。。。。难以想象
  5. 让人期待的Visual Studio 2010
  6. 洛谷 - P3321 [SDOI2015]序列统计(原根+NTT)
  7. CodeForces - 1323B Count Subrectangles(思维)
  8. POJ - 3614 Sunscreen(贪心/二分图最大匹配-多重匹配/网络流-最大流)
  9. CodeForces - 594A Warrior and Archer(思维+博弈)
  10. UVa11853 Paintball