跳至正文

【读书】Learning_SQL by Alan_Beaulieu-第五/十章 连接

标签:

Learning SQL读书笔记系列,最早于2023年春节期间,发布于微信公众号【格物致知】系列,一年后,整理到博客:


喜乐君按:数据准备是商业分析师绕不过去的关键门槛,也是考验一个人是否适合做数据分析的关键。特别是数据表连接,既考验对知识和工具的理解,又考验抽象化理解问题的能力。

本次先介绍使用SQL完成三级区域数据的处理,而后介绍learning SQL的第五章及第十章基本功能,稍后一个关键功能cross join结合案例单独成文。

Feb 3, 2022

1 · join案例–三级区域编码的自连接

针对具有层次结构的数据,通常需要多次join条件从而完成标准的数据格式,比如员工及直接上级、间接领导,比如县区的归属城市、归属省份等。

前段时间在客户的项目中,就遇到了这个问题,概括SQL是如何的好用,在特殊情况下,它会比Tableau更加敏捷。

我们先看一下数据表的字段和实例数据:

mysql> describe mdm_geo_info;+----------------+------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+----------------+------+------+-----+---------+-------+| DISTRICT_NAME | text | YES | | NULL | || PARENT_CODE | text | YES | | NULL | || DISTRICT_CODE | text | YES | | NULL | || DISTRICT_CLASS | text | YES | | NULL | |+----------------+------+------+-----+---------+-------+4 rows in set (0.01 sec)
mysql> select * from mdm_geo_info limit 10; +---------------+-------------+---------------+----------------+| DISTRICT_NAME | PARENT_CODE | DISTRICT_CODE | DISTRICT_CLASS |+---------------+-------------+---------------+----------------+| 站前区 | 210800 | 210802 | 县 || 清河门区 | 210900 | 210905 | 县 || 细河区 | 210900 | 210911 | 县 || 白塔区 | 211000 | 211002 | 县 || 开原市 | 211200 | 211282 | 县 || 龙城区 | 211300 | 211303 | 县 || 凌源市 | 211300 | 211382 | 县 || 农安县 | 220100 | 220122 | 县 || 公主岭市 | 220300 | 220381 | 县 || 龙山区 | 220400 | 220402 | 县 |+---------------+-------------+---------------+----------------+10 rows in set (0.00 sec)
mysql>

这里,district-name中包括了县区、城市、省份、国家多个层次,如何才能得到“县区-归属城市–归属省份”这样的数据结构,而非上面的底层结构呢?这样就需要join的多个方法:

  • use THE same table twice 
  • self-join

为了更好地理解这个过程,这里filter筛选 山东省的行政区划。

-- self-join and join twice 
mysql> select a.district_code  L3code, 
    -> a.district_name L3,
    -> b.district_name city,
    -> c.district_name province
    -> from  mdm_geo_info a 
    -> join mdm_geo_info  b  on a.parent_code = b.district_code
    -> join mdm_geo_info  c  on b.parent_code = c.district_code
    -> where c.district_name = '山东省';
+--------+--------------+-----------+-----------+
| L3code | L3           | city      | province  |
+--------+--------------+-----------+-----------+
| 370783 | 寿光市       | 潍坊市    | 山东省    |
| 370812 | 兖州区       | 济宁市    | 山东省    |
| 370921 | 宁阳县       | 泰安市    | 山东省    |
| 370983 | 肥城市       | 泰安市    | 山东省    |
| 371326 | 平邑县       | 临沂市    | 山东省    |
| 371402 | 德城区       | 德州市    | 山东省    |
| 371424 | 临邑县       | 德州市    | 山东省    |
……
| 371723 | 成武县       | 菏泽市    | 山东省    |
| 371702 | 牡丹区       | 菏泽市    | 山东省    |
| 371725 | 郓城县       | 菏泽市    | 山东省    |
+--------+--------------+-----------+-----------+
137 rows in set (0.02 sec)

这里,使用sql的self-join和join twice,可以在数据表中增加其他层次的数据,我们可以用图示如下所示:

当然,这里并非完美,这里默认的join是inner join,因为省份和城市默认也会显示,而它们后面的层级可能对应空,这将在后续通过outer join完成。

这里还增加了where条件,借助这个案例,可以更好地理解chapter 5的多表连接。


笔记部分

Chapter 5 Quering Multiple Tables (inner join)

大部分的分析都是建立在多表基础上的,这是因为ERP等底层软件的设计是追求稳定、性能和规范,而非追求业务过程的完整,因此完整的业务过程必然割裂为多表数据multiple tables。底层数据整合为业务过程数据,则是数据仓库等设计的基本任务。

1、Cartesian 笛卡尔

如果join没有指定连接字符,那么多表会生成笛卡尔积。笛卡尔积可以视为是多对多的相互匹配,table 1 的每一行都对应table2 的每一行,反之亦然。

因此,务必要正确地设置join后的condition条件,默认join就是inner join ,而条件通过on 子句来确认。

2、the ANSI join Syntax

目前普遍使用的SQL标准是 SQL92,它兼容之前的老标准,即把on的条件放到where条件中,不过显然目前不推荐这样做。书中强调了几个关键:(P86-87)

  • join condition and filter conditions are separated into two different clauses (the on subclause and the whereclause ,repectively), making a query easier to understand.
  • the join condition for each pair of tables are contained in their own on clause, making it less likely that part of a join will be mistakenly omitted. 
  • Queries that use the SQL92 join syntax are portable across database servers, whereas the older syntax is slightly different across the different servers. 

3、joining three or more Tables

多表连接和单表语法基本一致,保持 join 和on条件一致就好。

4、using Subquery as tables

多表join可以使用子查询subquery,在于理解多表的组合。而组合的背后其实是业务逻辑和场景的匹配。

子查询中,可以继续使用join关系,这样就可以层层嵌套下去。 

5、using the same table twice 

略,结合案例介绍(开篇)。

6、self-join自连接

join a table to itself. 

略,结合案例介绍(开篇)。

7、Equi-joins versus Non-Equi-joins 

通常的连接都是相同的判断,特殊情况下可以使用不相等判断,我在「客户迁徙分析」中有过介绍 。

在tableau中,不管是desktop的join还是relationship,还是prep的join,目前都已经支持这些连接方式。

语法和之前一样,重点在于合理的业务场景。这里先略过,后期结合案例介绍。

8、Join conditions versus filter conditions

join conditions和filter conditions都可以放在 where clause中,也可以放在on之中,虽然结果相同,但是建议区分二者,从而更好地理解,也就是说on只写连接条件,不写筛选条件 。

___ 

Chatper 10 Joins Revised (outer join)

Feb 3, 2022

相比第5章,这里更上一层楼,介绍了outer join,以及通过多次匹配创建日历表。

多表之间的关系,又可以参考chapter 6 working with sets中的set operators,我这里用一个图来表示。

数据表之间的关系,也是逻辑上的关系,只是是数据集set即多个数据之间的关系。数据表的A和B对数据结果有什么影响,我特别喜欢其中的一句话:

The keyword LEFT indicates that the table on the left side of the join is responsible for determing the number of rows in the result set,whereas the table on the right side is used to provide column values whenever a match is found. 

self outer joins 

Natural Joins

这个是之前我没有预料到的语法,它可以根据每个表的primary 和 foreign key 自动建立关联。不过,作者也不建议使用这个功能,特别是不确认字段是否完全一致的情况下。 

第10章还有一个重要的功能,cross join,它解决了一个很久以来的一个关键问题,因此单独成文介绍——【格物致知系列32篇】。