diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 60256f7..a5e4a2e --- a/README.md +++ b/README.md @@ -14,9 +14,11 @@ ### 视频资源 -1. [《Python零基础教程快速上手》](https://www.bilibili.com/video/BV1FT4y1R7sz) - Python基础部分的视频,因为随堂录制,有的时候声音会有点小,点赞过3000就为大家重新录制一套声音和画面都更好的精讲版视频。 -2. [《Python零基础数据库可视化教程》](https://www.bilibili.com/video/BV1dA411w7tu)- 数据库部分的视频,随堂录制,数据库部分讲得比较简单,后面还讲了一些做数据可视化系统的内容,我自己对这套视频不是很满意,点赞过2000之后就重新做一套面向数据分析师精讲数据库的视频,重点放在SQL和业务查询知识上,解决数据分析师日常提数问题。 -3. [《Scrapy爬虫框架教学》](https://www.bilibili.com/video/BV1QY411F7Vt)- 爬虫框架Scrapy教学视频,随堂录制,讲解了一个爬取淘宝商品信息的项目,有一点实用价值,爬虫本身并不是我感兴趣的内容,就将就看看吧。 +视频在抖音和B站都可以找到,有兴趣的小伙伴可以关注我的抖音或B站账号,刚刚起号,还希望大家多多支持,非常感谢! + +> **说明**:抖音对学习类的视频并不友好,我自己也不懂抖音的账号运营,目前基本不做抖音更新了,大家想看我的视频还是关注B站账号(下图左边的二维码),感谢大家的点赞关注,有什么想看的内容可以给我留言。 + + ### 文件资源 @@ -24,13 +26,8 @@ 链接:,提取码:swg1。 -### 交流大群 - -下面是我创建的学习交流群,欢迎加入一起学习共同进步。 - -1. 骆昊的Python学习群-1,群号:789050736,2000人大群。 -2. 骆昊的Python学习群-2,群号:837590310,2000人大群。 -3. 骆昊的Python学习群-3,群号:784430256,1000人大群。 +### 付费学习 - +之前创建的免费学习交流群(QQ群)都已经满员了,有学习意向的小伙伴可以加入付费交流群,新用户可以通过下方二维码付费之后添加我的私人微信(微信号:**jackfrued**),然后邀请大家进入付费学习打卡群,添加微信时请备注好自己的称呼和需求,我会为大家提供力所能及的帮助。 + diff --git a/res/20211121225327.png b/res/20211121225327.png new file mode 100755 index 0000000..6eee06a Binary files /dev/null and b/res/20211121225327.png differ diff --git a/res/pay_qr_code.png b/res/pay_qr_code.png new file mode 100644 index 0000000..3a861df Binary files /dev/null and b/res/pay_qr_code.png differ diff --git a/res/qq_groups.JPG b/res/qq_groups.JPG new file mode 100755 index 0000000..1d75d86 Binary files /dev/null and b/res/qq_groups.JPG differ diff --git a/res/qrcode.JPG b/res/qrcode.JPG new file mode 100755 index 0000000..8697cc0 Binary files /dev/null and b/res/qrcode.JPG differ diff --git "a/\347\254\25401\350\257\276\357\274\232\345\210\235\350\257\206Python.md" "b/\347\254\25401\350\257\276\357\274\232\345\210\235\350\257\206Python.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25402\350\257\276\357\274\232\347\254\254\344\270\200\344\270\252Python\347\250\213\345\272\217.md" "b/\347\254\25402\350\257\276\357\274\232\347\254\254\344\270\200\344\270\252Python\347\250\213\345\272\217.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25403\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\345\217\230\351\207\217.md" "b/\347\254\25403\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\345\217\230\351\207\217.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25404\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\350\277\220\347\256\227\347\254\246.md" "b/\347\254\25404\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\350\277\220\347\256\227\347\254\246.md" old mode 100644 new mode 100755 index 2cd74c5..13537f5 --- "a/\347\254\25404\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\350\277\220\347\256\227\347\254\246.md" +++ "b/\347\254\25404\350\257\276\357\274\232Python\350\257\255\350\250\200\345\205\203\347\264\240\344\271\213\350\277\220\347\256\227\347\254\246.md" @@ -17,7 +17,7 @@ Python语言支持很多种运算符,我们先用一个表格为大家列出 | `is` `is not` | 身份运算符 | | `in` `not in` | 成员运算符 | | `not` `or` `and` | 逻辑运算符 | -| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `|=` `^=` `>>=` `<<=` | (复合)赋值运算符 | +| `=` `+=` `-=` `*=` `/=` `%=` `//=` `**=` `&=` `\|=` `^=` `>>=` `<<=` | (复合)赋值运算符 | >**说明:** 上面这个表格实际上是按照运算符的优先级从上到下列出了各种运算符。所谓优先级就是在一个运算的表达式中,如果出现了多个运算符,应该先执行哪个运算再执行哪个运算的顺序。在实际开发中,如果搞不清楚运算符的优先级,可以使用圆括号来确保运算的执行顺序。 diff --git "a/\347\254\25405\350\257\276\357\274\232\345\210\206\346\224\257\347\273\223\346\236\204.md" "b/\347\254\25405\350\257\276\357\274\232\345\210\206\346\224\257\347\273\223\346\236\204.md" old mode 100644 new mode 100755 index d7908e5..9716940 --- "a/\347\254\25405\350\257\276\357\274\232\345\210\206\346\224\257\347\273\223\346\236\204.md" +++ "b/\347\254\25405\350\257\276\357\274\232\345\210\206\346\224\257\347\273\223\346\236\204.md" @@ -31,7 +31,7 @@ else: 如果要构造出更多的分支,可以使用`if...elif...else...`结构或者嵌套的`if...else...`结构,下面的代码演示了如何利用多分支结构实现分段函数求值。 $$ -f(x) = \begin{cases} 3x - 5, & (x \gt 1) \\ x + 2, & (-1 \le x \le 1) \\ 5x + 3, & (x \lt -1) \end{cases} +f(x) = \begin{cases} 3x - 5, & (x \gt 1) \\\\ x + 2, & (-1 \le x \le 1) \\\\ 5x + 3, & (x \lt -1) \end{cases} $$ ```Python diff --git "a/\347\254\25406\350\257\276\357\274\232\345\276\252\347\216\257\347\273\223\346\236\204.md" "b/\347\254\25406\350\257\276\357\274\232\345\276\252\347\216\257\347\273\223\346\236\204.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25407\350\257\276\357\274\232\345\210\206\346\224\257\345\222\214\345\276\252\347\216\257\347\273\223\346\236\204\347\232\204\345\272\224\347\224\250.md" "b/\347\254\25407\350\257\276\357\274\232\345\210\206\346\224\257\345\222\214\345\276\252\347\216\257\347\273\223\346\236\204\347\232\204\345\272\224\347\224\250.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25408\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\210\227\350\241\250.md" "b/\347\254\25408\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\210\227\350\241\250.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25409\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\205\203\347\273\204.md" "b/\347\254\25409\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\205\203\347\273\204.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25410\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\347\254\246\344\270\262.md" "b/\347\254\25410\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\347\254\246\344\270\262.md" old mode 100644 new mode 100755 index c872d40..56cda9a --- "a/\347\254\25410\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\347\254\246\344\270\262.md" +++ "b/\347\254\25410\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\347\254\246\344\270\262.md" @@ -9,9 +9,11 @@ ### 字符串的定义 所谓**字符串**,就是**由零个或多个字符组成的有限序列**,一般记为: + $$ s = a_1a_2 \cdots a_n \,\,\,\,\, (0 \le n \le \infty) $$ + 在Python程序中,如果我们把单个或多个字符用单引号或者双引号包围起来,就可以表示一个字符串。字符串中的字符可以是特殊符号、英文字母、中文字符、日文的平假名或片假名、希腊字母、[Emoji字符]()等。 ```Python diff --git "a/\347\254\25411\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\351\233\206\345\220\210.md" "b/\347\254\25411\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\351\233\206\345\220\210.md" old mode 100644 new mode 100755 index 7bbf566..c19ff16 --- "a/\347\254\25411\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\351\233\206\345\220\210.md" +++ "b/\347\254\25411\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\351\233\206\345\220\210.md" @@ -111,7 +111,7 @@ print(set1) # {3, 6} #### 比较运算 -两个集合可以用`==`和`!=`进行相等性判断,如果两个集合中的元素完全相同,那么`==`比较的结果就是`True`,否则就是`False`。如果集合`A`的任意一个元素都是集合`B`的元素,那么集合`A`称为集合`B`的子集,即对于$ \forall{a} \in {A}$,均有$ {a} \in {B} $,则$ {A} \subseteq {B} $,`A`是`B`的子集,反过来也可以称`B`是`A`的超集。如果`A`是`B`的子集且`A`不等于`B`,那么`A`就是`B`的真子集。Python为集合类型提供了判断子集和超集的运算符,其实就是我们非常熟悉的`<`和`>`运算符,代码如下所示。 +两个集合可以用`==`和`!=`进行相等性判断,如果两个集合中的元素完全相同,那么`==`比较的结果就是`True`,否则就是`False`。如果集合`A`的任意一个元素都是集合`B`的元素,那么集合`A`称为集合`B`的子集,即对于 $ \forall{a} \in {A}$ ,均有 $ {a} \in {B} $ ,则 $ {A} \subseteq {B} $ ,`A`是`B`的子集,反过来也可以称`B`是`A`的超集。如果`A`是`B`的子集且`A`不等于`B`,那么`A`就是`B`的真子集。Python为集合类型提供了判断子集和超集的运算符,其实就是我们非常熟悉的`<`和`>`运算符,代码如下所示。 ```Python set1 = {1, 3, 5} diff --git "a/\347\254\25412\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\345\205\270.md" "b/\347\254\25412\350\257\276\357\274\232\345\270\270\347\224\250\346\225\260\346\215\256\347\273\223\346\236\204\344\271\213\345\255\227\345\205\270.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25413\350\257\276\357\274\232\345\207\275\346\225\260\345\222\214\346\250\241\345\235\227.md" "b/\347\254\25413\350\257\276\357\274\232\345\207\275\346\225\260\345\222\214\346\250\241\345\235\227.md" old mode 100644 new mode 100755 index 3db76c7..c405f5d --- "a/\347\254\25413\350\257\276\357\274\232\345\207\275\346\225\260\345\222\214\346\250\241\345\235\227.md" +++ "b/\347\254\25413\350\257\276\357\274\232\345\207\275\346\225\260\345\222\214\346\250\241\345\235\227.md" @@ -1,14 +1,18 @@ ## 第13课:函数和模块 在讲解本节课的内容之前,我们先来研究一道数学题,请说出下面的方程有多少组正整数解。 + $$ x_1 + x_2 + x_3 + x_4 = 8 $$ -你可能已经想到了,这个问题其实等同于将`8`个苹果分成四组且每组至少一个苹果有多少种方案,因此该问题还可以进一步等价于在分隔`8`个苹果的`7`个空隙之间插入三个隔板将苹果分成四组有多少种方案,也就是从`7`个空隙选出`3`个空隙放入隔板的组合数,所以答案是$ C_7^3=35 $。组合数的计算公式如下所示。 + +你可能已经想到了,这个问题其实等同于将`8`个苹果分成四组且每组至少一个苹果有多少种方案,因此该问题还可以进一步等价于在分隔`8`个苹果的`7`个空隙之间插入三个隔板将苹果分成四组有多少种方案,也就是从`7`个空隙选出`3`个空隙放入隔板的组合数,所以答案是 $C_7^3=35$ 。组合数的计算公式如下所示。 + $$ C_M^N = \frac {M!} {N!(M-N)!} $$ -根据我们前面学习的知识,可以用循环做累乘的方式来计算阶乘,那么通过下面的Python代码我们就可以计算出组合数$ C_M^N $的值,代码如下所示。 + +根据我们前面学习的知识,可以用循环做累乘的方式来计算阶乘,那么通过下面的 Python 代码我们就可以计算出组合数 $C_M^N$ 的值,代码如下所示。 ```Python """ diff --git "a/\347\254\25414\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\345\272\224\347\224\250.md" "b/\347\254\25414\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\345\272\224\347\224\250.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25415\350\257\276\357\274\232\345\207\275\346\225\260\344\275\277\347\224\250\350\277\233\351\230\266.md" "b/\347\254\25415\350\257\276\357\274\232\345\207\275\346\225\260\344\275\277\347\224\250\350\277\233\351\230\266.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25416\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\351\253\230\347\272\247\345\272\224\347\224\250.md" "b/\347\254\25416\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\351\253\230\347\272\247\345\272\224\347\224\250.md" old mode 100644 new mode 100755 index 6521533..7ca7bc9 --- "a/\347\254\25416\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\351\253\230\347\272\247\345\272\224\347\224\250.md" +++ "b/\347\254\25416\350\257\276\357\274\232\345\207\275\346\225\260\347\232\204\351\253\230\347\272\247\345\272\224\347\224\250.md" @@ -168,7 +168,7 @@ upload('Python从新手到大师.pdf') ### 递归调用 -Python中允许函数嵌套定义,也允许函数之间相互调用,而且一个函数还可以直接或间接的调用自身。函数自己调用自己称为递归调用,那么递归调用有什么用处呢?现实中,有很多问题的定义本身就是一个递归定义,例如我们之前讲到的阶乘,非负整数`N`的阶乘是`N`乘以`N-1`的阶乘,即$ N! = N \times (N-1)! $,定义的左边和右边都出现了阶乘的概念,所以这是一个递归定义。既然如此,我们可以使用递归调用的方式来写一个求阶乘的函数,代码如下所示。 +Python中允许函数嵌套定义,也允许函数之间相互调用,而且一个函数还可以直接或间接的调用自身。函数自己调用自己称为递归调用,那么递归调用有什么用处呢?现实中,有很多问题的定义本身就是一个递归定义,例如我们之前讲到的阶乘,非负整数`N`的阶乘是`N`乘以`N-1`的阶乘,即 $ N! = N \times (N-1)! $ ,定义的左边和右边都出现了阶乘的概念,所以这是一个递归定义。既然如此,我们可以使用递归调用的方式来写一个求阶乘的函数,代码如下所示。 ```Python def fac(num): diff --git "a/\347\254\25417\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\205\245\351\227\250.md" "b/\347\254\25417\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\205\245\351\227\250.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25418\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\350\277\233\351\230\266.md" "b/\347\254\25418\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\350\277\233\351\230\266.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25419\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\272\224\347\224\250.md" "b/\347\254\25419\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\272\224\347\224\250.md" old mode 100644 new mode 100755 index e99062b..863a027 --- "a/\347\254\25419\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\272\224\347\224\250.md" +++ "b/\347\254\25419\350\257\276\357\274\232\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213\345\272\224\347\224\250.md" @@ -1,4 +1,4 @@ -## 第18课:面向对象编程应用 +## 第19课:面向对象编程应用 面向对象编程对初学者来说不难理解但很难应用,虽然我们为大家总结过面向对象的三步走方法(定义类、创建对象、给对象发消息),但是说起来容易做起来难。**大量的编程练习**和**阅读优质的代码**可能是这个阶段最能够帮助到大家的两件事情。接下来我们还是通过经典的案例来剖析面向对象编程的知识,同时也通过这些案例为大家讲解如何运用之前学过的Python知识。 diff --git "a/\347\254\25420\350\257\276\357\274\232Python\346\240\207\345\207\206\345\272\223\345\210\235\346\216\242.md" "b/\347\254\25420\350\257\276\357\274\232Python\346\240\207\345\207\206\345\272\223\345\210\235\346\216\242.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25421\350\257\276\357\274\232\346\226\207\344\273\266\350\257\273\345\206\231\345\222\214\345\274\202\345\270\270\345\244\204\347\220\206.md" "b/\347\254\25421\350\257\276\357\274\232\346\226\207\344\273\266\350\257\273\345\206\231\345\222\214\345\274\202\345\270\270\345\244\204\347\220\206.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25422\350\257\276\357\274\232\345\257\271\350\261\241\347\232\204\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md" "b/\347\254\25422\350\257\276\357\274\232\345\257\271\350\261\241\347\232\204\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25423\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231CSV\346\226\207\344\273\266.md" "b/\347\254\25423\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231CSV\346\226\207\344\273\266.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25424\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231Excel\346\226\207\344\273\266-1.md" "b/\347\254\25424\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231Excel\346\226\207\344\273\266-1.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25425\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231Excel\346\226\207\344\273\266-2.md" "b/\347\254\25425\350\257\276\357\274\232\347\224\250Python\350\257\273\345\206\231Excel\346\226\207\344\273\266-2.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25426\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234Word\346\226\207\344\273\266\345\222\214PowerPoint.md" "b/\347\254\25426\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234Word\346\226\207\344\273\266\345\222\214PowerPoint.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25427\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234PDF\346\226\207\344\273\266.md" "b/\347\254\25427\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234PDF\346\226\207\344\273\266.md" old mode 100644 new mode 100755 index 4177f54..6825f83 --- "a/\347\254\25427\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234PDF\346\226\207\344\273\266.md" +++ "b/\347\254\25427\350\257\276\357\274\232\347\224\250Python\346\223\215\344\275\234PDF\346\226\207\344\273\266.md" @@ -15,9 +15,9 @@ pip install PyPDF2 ```Python import PyPDF2 -reader = PyPDF2.PdfFileReader('test.pdf') -page = reader.getPage(0) -print(page.extractText()) +reader = PyPDF2.PdfReader('test.pdf') +for page in reader.pages: + print(page.extract_text()) ``` > **提示**:上面代码中使用的PDF文件“test.pdf”以及下面的代码中需要用到的PDF文件,也可以通过下面的百度云盘地址进行获取。链接:https://pan.baidu.com/s/1rQujl5RQn9R7PadB2Z5g_g 提取码:e7b4。 @@ -36,31 +36,18 @@ pdf2text.py test.pdf 上面的代码中通过创建`PdfFileReader`对象的方式来读取PDF文档,该对象的`getPage`方法可以获得PDF文档的指定页并得到一个`PageObject`对象,通过`PageObject`对象的`rotateClockwise`和`rotateCounterClockwise`方法可以实现页面的顺时针和逆时针方向旋转,通过`PageObject`对象的`addBlankPage`方法可以添加一个新的空白页,代码如下所示。 ```Python -import PyPDF2 +reader = PyPDF2.PdfReader('XGBoost.pdf') +writer = PyPDF2.PdfWriter() -from PyPDF2.pdf import PageObject - -# 创建一个读PDF文件的Reader对象 -reader = PyPDF2.PdfFileReader('resources/XGBoost.pdf') -# 创建一个写PDF文件的Writer对象 -writer = PyPDF2.PdfFileWriter() -# 对PDF文件所有页进行循环遍历 -for page_num in range(reader.numPages): - # 获取指定页码的Page对象 - current_page = reader.getPage(page_num) # type: PageObject - if page_num % 2 == 0: - # 奇数页顺时针旋转90度 - current_page.rotateClockwise(90) +for no, page in enumerate(reader.pages): + if no % 2 == 0: + new_page = page.rotate(-90) else: - # 偶数页反时针旋转90度 - current_page.rotateCounterClockwise(90) - writer.addPage(current_page) -# 最后添加一个空白页并旋转90度 -page = writer.addBlankPage() # type: PageObject -page.rotateClockwise(90) -# 通过Writer对象的write方法将PDF写入文件 -with open('resources/XGBoost-modified.pdf', 'wb') as file: - writer.write(file) + new_page = page.rotate(90) + writer.add_page(new_page) + +with open('temp.pdf', 'wb') as file_obj: + writer.write(file_obj) ``` ### 加密PDF文件 @@ -70,14 +57,16 @@ with open('resources/XGBoost-modified.pdf', 'wb') as file: ```Python import PyPDF2 -reader = PyPDF2.PdfFileReader('resources/XGBoost.pdf') -writer = PyPDF2.PdfFileWriter() -for page_num in range(reader.numPages): - writer.addPage(reader.getPage(page_num)) -# 通过encrypt方法加密PDF文件,方法的参数就是设置的密码 +reader = PyPDF2.PdfReader('XGBoost.pdf') +writer = PyPDF2.PdfWriter() + +for page in reader.pages: + writer.add_page(page) + writer.encrypt('foobared') -with open('resources/XGBoost-encrypted.pdf', 'wb') as file: - writer.write(file) + +with open('temp.pdf', 'wb') as file_obj: + writer.write(file_obj) ``` ### 批量添加水印 @@ -85,23 +74,17 @@ with open('resources/XGBoost-encrypted.pdf', 'wb') as file: 上面提到的`PageObject`对象还有一个名为`mergePage`的方法,可以两个PDF页面进行叠加,通过这个操作,我们很容易实现给PDF文件添加水印的功能。例如要给上面的“XGBoost.pdf”文件添加一个水印,我们可以先准备好一个提供水印页面的PDF文件,然后将包含水印的`PageObject`读取出来,然后再循环遍历“XGBoost.pdf”文件的每个页,获取到`PageObject`对象,然后通过`mergePage`方法实现水印页和原始页的合并,代码如下所示。 ```Python -import PyPDF2 +reader1 = PyPDF2.PdfReader('XGBoost.pdf') +reader2 = PyPDF2.PdfReader('watermark.pdf') +writer = PyPDF2.PdfWriter() +watermark_page = reader2.pages[0] + +for page in reader1.pages: + page.merge_page(watermark_page) + writer.add_page(page) -from PyPDF2.pdf import PageObject - -reader1 = PyPDF2.PdfFileReader('resources/XGBoost.pdf') -reader2 = PyPDF2.PdfFileReader('resources/watermark.pdf') -writer = PyPDF2.PdfFileWriter() -# 获取水印页 -watermark_page = reader2.getPage(0) -for page_num in range(reader1.numPages): - current_page = reader1.getPage(page_num) # type: PageObject - current_page.mergePage(watermark_page) - # 将原始页和水印页进行合并 - writer.addPage(current_page) -# 将PDF写入文件 -with open('resources/XGBoost-watermarked.pdf', 'wb') as file: - writer.write(file) +with open('temp.pdf', 'wb') as file_obj: + writer.write(file_obj) ``` 如果愿意,还可以让奇数页和偶数页使用不同的水印,大家可以自己思考下应该怎么做。 diff --git "a/\347\254\25428\350\257\276\357\274\232\347\224\250Python\345\244\204\347\220\206\345\233\276\345\203\217.md" "b/\347\254\25428\350\257\276\357\274\232\347\224\250Python\345\244\204\347\220\206\345\233\276\345\203\217.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25429\350\257\276\357\274\232\347\224\250Python\345\217\221\351\200\201\351\202\256\344\273\266\345\222\214\347\237\255\344\277\241.md" "b/\347\254\25429\350\257\276\357\274\232\347\224\250Python\345\217\221\351\200\201\351\202\256\344\273\266\345\222\214\347\237\255\344\277\241.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25430\350\257\276\357\274\232\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\347\232\204\345\272\224\347\224\250.md" "b/\347\254\25430\350\257\276\357\274\232\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\347\232\204\345\272\224\347\224\250.md" old mode 100644 new mode 100755 index 940daa2..3b9d4bc --- "a/\347\254\25430\350\257\276\357\274\232\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\347\232\204\345\272\224\347\224\250.md" +++ "b/\347\254\25430\350\257\276\357\274\232\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\347\232\204\345\272\224\347\224\250.md" @@ -31,7 +31,7 @@ | `{N}` | 匹配N次 | `\w{3}` | | | `{M,}` | 匹配至少M次 | `\w{3,}` | | | `{M,N}` | 匹配至少M次至多N次 | `\w{3,6}` | | -| `|` | 分支 | `foo|bar` | 可以匹配foo或者bar | +| `\|` | 分支 | `foo\|bar` | 可以匹配foo或者bar | | `(?#)` | 注释 | | | | `(exp)` | 匹配exp并捕获到自动命名的组中 | | | | `(?exp)` | 匹配exp并捕获到名为name的组中 | | | diff --git "a/\347\254\25431\350\257\276\357\274\232\347\275\221\347\273\234\346\225\260\346\215\256\351\207\207\351\233\206\346\246\202\350\277\260.md" "b/\347\254\25431\350\257\276\357\274\232\347\275\221\347\273\234\346\225\260\346\215\256\351\207\207\351\233\206\346\246\202\350\277\260.md" old mode 100644 new mode 100755 index cc101a1..cf5db48 --- "a/\347\254\25431\350\257\276\357\274\232\347\275\221\347\273\234\346\225\260\346\215\256\351\207\207\351\233\206\346\246\202\350\277\260.md" +++ "b/\347\254\25431\350\257\276\357\274\232\347\275\221\347\273\234\346\225\260\346\215\256\351\207\207\351\233\206\346\246\202\350\277\260.md" @@ -40,7 +40,7 @@ Disallow: / 图1. 百度搜索淘宝的结果 -![](https://github.com/jackfrued/mypic/raw/master/20210824004320.png) +![](http://localhost/mypic/20210824004320.png) 下面是豆瓣网的[`robots.txt`](https://www.douban.com/robots.txt)文件,大家可以自行解读,看看它做出了什么样的限制。 @@ -89,19 +89,19 @@ Disallow: /j/ 图2. HTTP请求 -![http-request](https://github.com/jackfrued/mypic/raw/master/20210824003915.png) +![http-request](http://localhost/mypic/20210824003915.png) HTTP 请求通常是由请求行、请求头、空行、消息体四个部分构成,如果没有数据发给服务器,消息体就不是必须的部分。请求行中包含了请求方法(GET、POST 等,如下表所示)、资源路径和协议版本;请求头由若干键值对构成,包含了浏览器、编码方式、首选语言、缓存策略等信息;请求头的后面是空行和消息体。 - + 图3. HTTP响应 -![http-response](https://github.com/jackfrued/mypic/raw/master/20210824234158.png) +![http-response](http://localhost/mypic/20210824234158.png) HTTP 响应通常是由响应行、响应头、空行、消息体四个部分构成,其中消息体是服务响应的数据,可能是 HTML 页面,也有可能是JSON或二进制数据等。响应行中包含了协议版本和响应状态码,响应状态码有很多种,常见的如下表所示。 - + #### 相关工具 @@ -115,11 +115,11 @@ HTTP 响应通常是由响应行、响应头、空行、消息体四个部分构 - 网络(Network):用于 HTTP 请求、HTTP 响应以及与网络连接相关的信息。 - 应用(Application):用于查看浏览器本地存储、后台任务等内容,本地存储主要包括Cookie、Local Storage、Session Storage等。 - ![chrome-developer-tools](https://github.com/jackfrued/mypic/raw/master/20210824004034.png) + ![chrome-developer-tools](http://localhost/mypic/20210824004034.png) 2. Postman:功能强大的网页调试与 RESTful 请求工具。Postman可以帮助我们模拟请求,非常方便的定制我们的请求以及查看服务器的响应。 - ![postman](https://github.com/jackfrued/mypic/raw/master/20210824004048.png) + ![postman](http://localhost/mypic/20210824004048.png) 3. HTTPie:命令行HTTP客户端。 @@ -187,7 +187,7 @@ HTTP 响应通常是由响应行、响应头、空行、消息体四个部分构 一个基本的爬虫通常分为数据采集(网页下载)、数据处理(网页解析)和数据存储(将有用的信息持久化)三个部分的内容,当然更为高级的爬虫在数据采集和处理时会使用并发编程或分布式技术,这就需要有调度器(安排线程或进程执行对应的任务)、后台管理程序(监控爬虫的工作状态以及检查数据抓取的结果)等的参与。 -![crawler-workflow](https://github.com/jackfrued/mypic/raw/master/20210824004107.png) +![](http://localhost/mypic/20210824004107.png) 一般来说,爬虫的工作流程包括以下几个步骤: diff --git "a/\347\254\25432\350\257\276\357\274\232\347\224\250Python\350\216\267\345\217\226\347\275\221\347\273\234\350\265\204\346\272\220.md" "b/\347\254\25432\350\257\276\357\274\232\347\224\250Python\350\216\267\345\217\226\347\275\221\347\273\234\350\265\204\346\272\220.md" old mode 100644 new mode 100755 index e182131..0152cee --- "a/\347\254\25432\350\257\276\357\274\232\347\224\250Python\350\216\267\345\217\226\347\275\221\347\273\234\350\265\204\346\272\220.md" +++ "b/\347\254\25432\350\257\276\357\274\232\347\224\250Python\350\216\267\345\217\226\347\275\221\347\273\234\350\265\204\346\272\220.md" @@ -6,7 +6,7 @@ 要使用 Python 获取网络数据,我们推荐大家使用名为`requests` 的三方库,这个库我们在之前的课程中其实已经使用过了。按照官方网站的解释,`requests`是基于 Python 标准库进行了封装,简化了通过 HTTP 或 HTTPS 访问网络资源的操作。上课我们提到过,HTTP 是一个请求响应式的协议,当我们在浏览器中输入正确的 [URL](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/What_is_a_URL)(通常也称为网址)并按下 Enter 键时,我们就向网络上的 [Web 服务器](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/What_is_a_web_server)发送了一个 HTTP 请求,服务器在收到请求后会给我们一个 HTTP 响应。在 Chrome 浏览器中的菜单中打开“开发者工具”切换到“Network”选项卡就能够查看 HTTP 请求和响应到底是什么样子的,如下图所示。 -![](https://github.com/jackfrued/mypic/raw/master/20210822093434.png) +![](http://localhost/mypic/20210822093434.png) 通过`requests`库,我们可以让 Python 程序向浏览器一样向 Web 服务器发起请求,并接收服务器返回的响应,从响应中我们就可以提取出想要的数据。浏览器呈现给我们的网页是用 [HTML](https://developer.mozilla.org/zh-CN/docs/Web/HTML) 编写的,浏览器相当于是 HTML 的解释器环境,我们看到的网页中的内容都包含在 HTML 的标签中。在获取到 HTML 代码后,就可以从标签的属性或标签体中提取内容。下面例子演示了如何获取网页 HTML 代码,我们通过`requests`库的`get`函数,获取了搜狐首页的代码。 @@ -54,7 +54,7 @@ with open('baidu.png', 'wb') as file: 接下来,我们以“豆瓣电影”为例,为大家讲解如何编写爬虫代码。按照上面提供的方法,我们先使用`requests`获取到网页的HTML代码,然后将整个代码看成一个长字符串,这样我们就可以使用正则表达式的捕获组从字符串提取我们需要的内容。下面的代码演示了如何从[豆瓣电影](https://movie.douban.com/)获取排前250名的电影的名称。[豆瓣电影Top250](https://movie.douban.com/top250)的页面结构和对应代码如下图所示,可以看出,每页共展示了25部电影,如果要获取到 Top250 数据,我们共需要访问10个页面,对应的地址是,这里的`xxx`如果为`0`就是第一页,如果`xxx`的值是`100`,那么我们可以访问到第五页。为了代码简单易读,我们只获取电影的标题和评分。 -![](https://github.com/jackfrued/mypic/raw/master/20210822093447.png) +![](http://localhost/mypic/20210822093447.png) ```Python import random @@ -92,7 +92,7 @@ for page in range(1, 11): 下面以[蘑菇代理](http://www.moguproxy.com/)为例,为大家讲解商业 IP 代理的使用方法。首先需要在该网站注册一个账号,注册账号后就可以[购买](http://www.moguproxy.com/buy)相应的套餐来获得商业 IP 代理。作为商业用途,建议大家购买不限量套餐,这样可以根据实际需要获取足够多的代理 IP 地址;作为学习用途,可以购买包时套餐或根据自己的需求来决定。蘑菇代理提供了两种接入代理的方式,分别是 API 私密代理和 HTTP 隧道代理,前者是通过请求蘑菇代理的 API 接口获取代理服务器地址,后者是直接使用统一的入口(蘑菇代理提供的域名)进行接入。 - + 下面,我们以HTTP隧道代理为例,为大家讲解接入 IP 代理的方式,大家也可以直接参考蘑菇代理官网提供的代码来为爬虫设置代理。 diff --git "a/\347\254\25433\350\257\276\357\274\232\347\224\250Python\350\247\243\346\236\220HTML\351\241\265\351\235\242.md" "b/\347\254\25433\350\257\276\357\274\232\347\224\250Python\350\247\243\346\236\220HTML\351\241\265\351\235\242.md" old mode 100644 new mode 100755 index 309471d..f893b88 --- "a/\347\254\25433\350\257\276\357\274\232\347\224\250Python\350\247\243\346\236\220HTML\351\241\265\351\235\242.md" +++ "b/\347\254\25433\350\257\276\357\274\232\347\224\250Python\350\247\243\346\236\220HTML\351\241\265\351\235\242.md" @@ -36,7 +36,7 @@ XPath 是在 XML(eXtensible Markup Language)文档中查找信息的一种 29.99 - Learning XML + Learning XML 39.95 diff --git "a/\347\254\25434\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" "b/\347\254\25434\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25435\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-2.md" "b/\347\254\25435\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-2.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25436\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-3.md" "b/\347\254\25436\350\257\276\357\274\232Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-3.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25437\350\257\276\357\274\232\345\271\266\345\217\221\347\274\226\347\250\213\345\234\250\347\210\254\350\231\253\344\270\255\347\232\204\345\272\224\347\224\250.md" "b/\347\254\25437\350\257\276\357\274\232\345\271\266\345\217\221\347\274\226\347\250\213\345\234\250\347\210\254\350\231\253\344\270\255\347\232\204\345\272\224\347\224\250.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25438\350\257\276\357\274\232\346\212\223\345\217\226\347\275\221\351\241\265\345\212\250\346\200\201\345\206\205\345\256\271.md" "b/\347\254\25438\350\257\276\357\274\232\346\212\223\345\217\226\347\275\221\351\241\265\345\212\250\346\200\201\345\206\205\345\256\271.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25439\350\257\276\357\274\232\347\210\254\350\231\253\346\241\206\346\236\266Scrapy\347\256\200\344\273\213.md" "b/\347\254\25439\350\257\276\357\274\232\347\210\254\350\231\253\346\241\206\346\236\266Scrapy\347\256\200\344\273\213.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25440\350\257\276\357\274\232\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\345\222\214MySQL\346\246\202\350\277\260.md" "b/\347\254\25440\350\257\276\357\274\232\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\345\222\214MySQL\346\246\202\350\277\260.md" old mode 100644 new mode 100755 diff --git "a/\347\254\25441\350\257\276.SQL\350\257\246\350\247\243\344\271\213DDL.md" "b/\347\254\25441\350\257\276.SQL\350\257\246\350\247\243\344\271\213DDL.md" old mode 100644 new mode 100755 index 9bd11f7..55c5b51 --- "a/\347\254\25441\350\257\276.SQL\350\257\246\350\247\243\344\271\213DDL.md" +++ "b/\347\254\25441\350\257\276.SQL\350\257\246\350\247\243\344\271\213DDL.md" @@ -1,4 +1,4 @@ -## SQL详解之DDL +## 第41课:SQL详解之DDL 我们通常可以将 SQL 分为四类,分别是 DDL(数据定义语言)、DML(数据操作语言)、DQL(数据查询语言)和 DCL(数据控制语言)。DDL 主要用于创建、删除、修改数据库中的对象,比如创建、删除和修改二维表,核心的关键字包括`create`、`drop`和`alter`;DML 主要负责数据的插入、删除和更新,关键词包括`insert`、`delete`和`update`;DQL 负责数据查询,最重要的一个关键词是`select`;DCL 通常用于授予和召回权限,核心关键词是`grant`和`revoke`。 diff --git "a/\347\254\25442\350\257\276.SQL\350\257\246\350\247\243\344\271\213DML.md" "b/\347\254\25442\350\257\276.SQL\350\257\246\350\247\243\344\271\213DML.md" old mode 100644 new mode 100755 index 78f28db..a7e83ed --- "a/\347\254\25442\350\257\276.SQL\350\257\246\350\247\243\344\271\213DML.md" +++ "b/\347\254\25442\350\257\276.SQL\350\257\246\350\247\243\344\271\213DML.md" @@ -1,4 +1,4 @@ -## SQL详解之DML +## 第42课:SQL详解之DML 我们接着上一课中创建的学校选课系统数据库,为大家讲解 DML 的使用。DML 可以帮助将数据插入到二维表(`insert`操作)、从二维表删除数据(`delete`操作)以及更新二维表的数据(`update`操作)。在执行 DML 之前,我们先通过下面的`use`命令切换到`school`数据库。 diff --git "a/\347\254\25443\350\257\276.SQL\350\257\246\350\247\243\344\271\213DQL.md" "b/\347\254\25443\350\257\276.SQL\350\257\246\350\247\243\344\271\213DQL.md" old mode 100644 new mode 100755 index 480d1c7..418f050 --- "a/\347\254\25443\350\257\276.SQL\350\257\246\350\247\243\344\271\213DQL.md" +++ "b/\347\254\25443\350\257\276.SQL\350\257\246\350\247\243\344\271\213DQL.md" @@ -1,370 +1,415 @@ -## SQL详解之DQL +## 第43课:SQL详解之DQL 接下来,我们利用之前创建的学校选课系统数据库,为大家讲解 DQL 的应用。无论对于开发人员还是数据分析师,DQL 都是非常重要的,它关系着我们能否从关系数据库中获取我们需要的数据。建议大家把上上一节课中建库建表的 DDL 以及 上一节课中插入数据的 DML 重新执行一次,确保表和数据跟没有问题再执行下面的操作。 ```SQL use `school`; --- 查询所有学生的所有信息 --- 说明:实际工作中不建议使用 select * 的方式进行查询 -select * - from tb_student; - --- 查询学生的学号、姓名和籍贯 -select stu_id, - stu_name, - stu_addr - from tb_student; +-- 01. 查询所有学生的所有信息 +select * + from tb_student; -select stu_id as 学号, - stu_name as 姓名, - stu_addr as 籍贯 - from tb_student; - --- 查询所有课程的名称及学分 -select cou_name as 课程名称, - cou_credit as 学分 - from tb_course; - --- 查询所有女学生的姓名和出生日期 -select stu_name, - stu_birth - from tb_student - where stu_sex=0; - --- 查询籍贯为“四川成都”的女学生的姓名和出生日期 -select stu_name, - stu_birth - from tb_student - where stu_sex=0 - and stu_addr='四川成都'; - --- 查询籍贯为“四川成都”或者性别是女的学生 -select stu_name, - stu_birth - from tb_student - where stu_sex=0 - or stu_addr='四川成都'; - --- 查询所有80后学生的姓名、性别和出生日期 --- 方法一: -select stu_name, - stu_sex, - stu_birth - from tb_student - where stu_birth >= '1980-1-1' - and stu_birth <= '1989-12-31'; - --- 方法二: -select stu_name, - stu_sex, - stu_birth - from tb_student - where stu_birth between '1980-1-1' and '1989-12-31'; - --- 查询学分大于2的课程的名称和学分 -select cou_name, - cou_credit - from tb_course - where cou_credit > 2; - --- 查询学分是奇数的课程的名称和学分 -select cou_name, - cou_credit - from tb_course - where cou_credit % 2 <> 0; - --- 查询选择选了1111的课程考试成绩在90分以上的学生学号 -select stu_id - from tb_record - where cou_id = 1111 - and score > 90; +select stu_id + , stu_name + , stu_sex + , stu_birth + , stu_addr + , col_id + from tb_student; + +-- 02. 查询学生的学号、姓名和籍贯(投影和别名) +select stu_id as 学号 + , stu_name as 姓名 + , stu_addr as 籍贯 + from tb_student; + +-- 03. 查询所有课程的名称及学分(投影和别名) +select cou_name as 课程名称 + , cou_credit as 学分 + from tb_course; + +-- 04. 查询所有女学生的姓名和出生日期(数据筛选) +select stu_name + , stu_birth + from tb_student + where stu_sex = 0; + +-- 05. 查询籍贯为“四川成都”的女学生的姓名和出生日期(数据筛选) +select stu_name + , stu_birth + from tb_student + where stu_sex = 0 and stu_addr = '四川成都'; + +-- 06. 查询籍贯为“四川成都”或者性别是女的学生(数据筛选) +select stu_name + , stu_birth + from tb_student + where stu_sex = 0 or stu_addr = '四川成都'; + +-- 07. 查询所有80后学生的姓名、性别和出生日期(数据筛选) +select stu_name + , stu_sex + , stu_birth + from tb_student + where '1980-1-1' <= stu_birth and stu_birth <= '1989-12-31'; + +select stu_name + , stu_sex + , stu_birth + from tb_student + where stu_birth between '1980-1-1' and '1989-12-31'; + +-- MySQL方言 +select stu_name + , if(stu_sex, '男', '女') as stu_sex + , stu_birth + from tb_student + where stu_birth between '1980-1-1' and '1989-12-31'; + +select stu_name + , case stu_sex + when 1 then '男' + else '女' + end as stu_sex + , stu_birth + from tb_student + where stu_birth between '1980-1-1' and '1989-12-31'; + +-- 08. 查询学分大于2分的课程名称和学分(数据筛选) +select cou_name + , cou_credit + from tb_course + where cou_credit > 2; + +-- 09. 查询学分是奇数的课程的名称和学分(数据筛选) +select cou_name + , cou_credit + from tb_course + where cou_credit mod 2 <> 0; + +-- 10. 查询选择选了1111的课程考试成绩在90分以上的学生学号(数据筛选) +select stu_id + from tb_record + where cou_id = 1111 and score > 90; + +-- 11. 查询名字叫“杨过”的学生的姓名和性别 +select stu_name + , stu_sex + from tb_student + where stu_name = '杨过'; + +-- 12. 查询姓“杨”的学生姓名和性别(模糊查询) +-- wild card - 通配符 - % - 代表零个或任意多个字符 +select stu_name + , stu_sex + from tb_student + where stu_name like '杨%'; + +-- 13. 查询姓“杨”名字两个字的学生姓名和性别(模糊查询) +-- wild card - 通配符 - _ - 精确匹配一个字符 +select stu_name + , stu_sex + from tb_student + where stu_name like '杨_'; + +-- 14. 查询姓“杨”名字三个字的学生姓名和性别(模糊查询) +select stu_name + , stu_sex + from tb_student + where stu_name like '杨__'; + +-- 15. 查询名字中有“不”字或“嫣”字的学生的姓名(模糊查询) +select stu_name + from tb_student + where stu_name like '%不%' or stu_name like '%嫣%'; --- 查询姓“杨”的学生姓名和性别(模糊) --- % 可以匹配零个或任意多个字符 -select stu_name, - stu_sex - from tb_student - where stu_name like '杨%'; - --- 查询姓“杨”名字两个字的学生姓名和性别(模糊) --- _ 可以匹配一个字符 -select stu_name, - stu_sex - from tb_student - where stu_name like '杨_'; - --- 查询姓“杨”名字三个字的学生姓名和性别(模糊) -select stu_name, - stu_sex - from tb_student - where stu_name like '杨__'; - --- 查询名字中有“不”字或“嫣”字的学生的姓名(模糊) --- 方法一: -select stu_name, - stu_sex - from tb_student - where stu_name like '%不%' - or stu_name like '%嫣%'; - --- 方法二: -select stu_name, - stu_sex - from tb_student - where stu_name like '%不%' +select stu_name + from tb_student + where stu_name like '%不%' union -select stu_name, - stu_sex - from tb_student - where stu_name like '%嫣%'; - --- 查询姓“杨”或姓“林”名字三个字的学生的姓名 -select stu_name, - stu_sex - from tb_student - where stu_name regexp '^[杨林][\\u4e00-\\u9fa5]{2}$'; - --- 查询没有录入籍贯的学生姓名 -select stu_name - from tb_student - where stu_addr = '' - or stu_addr is null; - --- 查询录入了籍贯的学生姓名 -select stu_name - from tb_student - where stu_addr <> '' - and stu_addr is not null; - --- 查询学生选课的所有日期 -select distinct sel_date - from tb_record; - --- 查询学生的籍贯 -select distinct stu_addr - from tb_student - where stu_addr <> '' - and stu_addr is not null; - --- 查询学院编号为1的学生姓名、性别和生日按年龄从大到小排列 --- asc - 升序(从小到大,默认),desc - 降序(从大到小) - select stu_name, - stu_sex, - stu_birth - from tb_student - where col_id = 1 -order by stu_sex asc, - stu_birth asc; - --- 补充:将上面的性别处理成“男”或“女”,将生日换算成年龄 - select stu_name as 姓名, - if(stu_sex, '男', '女') as 性别, - floor(datediff(curdate(), stu_birth) / 365) as 年龄 - from tb_student - where col_id = 1 -order by stu_sex asc, - 年龄 desc; - --- 查询年龄最大的学生的出生日期 -select min(stu_birth) - from tb_student; - --- 查询年龄最小的学生的出生日期 -select max(stu_birth) - from tb_student; - --- 查询学号为1001的学生一共选了几门课 -select count(*) - from tb_record - where stu_id = 1001; - --- 查询学号为1001的学生考试成绩的平均分 -select round(avg(score), 1) as 平均分 - from tb_record - where stu_id = 1001; - --- 查询学号为1001的学生考试成绩的平均分,如果有null值,null值算0分 --- 方法一: -select sum(score) / count(*) - from tb_record - where stu_id = 1001; +select stu_name + from tb_student + where stu_name like '%嫣%'; + +update tb_student + set stu_name = '岳不嫣' + where stu_id = 1572; + +select stu_name + from tb_student + where stu_name like '%不%' + union all +select stu_name + from tb_student + where stu_name like '%嫣%'; + +-- 16. 查询姓“杨”或姓“林”名字三个字的学生的姓名(正则表达式模糊查询) +-- regular expression +select stu_name + from tb_student + where stu_name regexp '[杨林][\\u4e00-\\u9fa5]{2}'; + +-- 17. 查询没有录入籍贯的学生姓名(空值处理) +select stu_name + from tb_student + where stu_addr is null or trim(stu_addr) = ''; + +update tb_student + set stu_addr = ' ' + where stu_id = 1572; + +-- 18. 查询录入了籍贯的学生姓名(空值处理) +select stu_name + from tb_student + where stu_addr is not null and trim(stu_addr) <> ''; + +-- 19. 查询学生选课的所有日期(去重) +select distinct sel_date + from tb_record; + +-- 20. 查询学生的籍贯(空值处理和去重) +select distinct stu_addr + from tb_student + where stu_addr is not null and trim(stu_addr) <> ''; + +-- 21. 查询男学生的姓名和生日按年龄从大到小排列(排序) +-- ascending / descending +select stu_name + , stu_birth + from tb_student + where stu_sex = 1 + order by stu_birth asc; + +-- 22. 将上面查询中的生日换算成年龄(日期函数、数值函数) +-- 获取当前日期:curdate() +-- 计算时间差:timestampdiff(unit, date1, date2) +select stu_name + , timestampdiff(year, stu_birth, curdate()) as stu_age + from tb_student + where stu_sex = 1 + order by stu_age desc; + +-- 聚合函数:max / min / avg / sum / count / std / variance +-- 聚合函数会自动忽略掉null +-- 23. 查询年龄最大的学生的出生日期(聚合函数) +select min(stu_birth) + from tb_student; + +-- 24. 查询年龄最小的学生的出生日期(聚合函数) +select max(stu_birth) + from tb_student; + +-- 25. 查询编号为1111的课程考试成绩的最高分(聚合函数) +select max(score) + from tb_record + where cou_id = 1111; + +-- 26. 查询学号为1001的学生考试成绩的最低分(聚合函数) +select min(score) + from tb_record + where stu_id = 1001; + +-- 27. 查询学号为1001的学生考试成绩的平均分和标准差(聚合函数) +-- 四舍五入函数:round(num, n) +select round(avg(score), 1) as avg_score + , round(std(score), 4) as std_score + from tb_record + where stu_id = 1001; + +-- 28. 查询学号为1001的学生考试成绩的平均分,如果有null值,null值算0分(聚合函数) +select sum(score) / count(*) + from tb_record + where stu_id = 1001; + +-- 29. 查询男女学生的人数(分组和聚合函数) +select case stu_sex when 1 then '男' else '女' end as stu_sex + , count(*) as total + from tb_student + group by stu_sex; + +-- 30. 查询每个学院学生人数(分组和聚合函数) +select col_id + , count(*) as total + from tb_student + group by col_id + with rollup; + +-- 31. 查询每个学院男女学生人数(分组和聚合函数) +select col_id + , case stu_sex when 1 then '男' else '女' end as stu_sex + , count(*) as total + from tb_student + group by col_id, stu_sex; + +-- 32. 查询选课学生的学号和平均成绩(分组和聚合函数) +select stu_id + , round(avg(score), 1) as avg_score + from tb_record + group by stu_id; + +-- 33. 查询平均成绩大于等于90分的学生的学号和平均成绩(分组和聚合函数) +-- 结论:分组前的筛选使用where子句,分组后的筛选使用having子句 +select stu_id + , round(avg(score), 1) as avg_score + from tb_record + group by stu_id +having avg(score) >= 90; + +-- 34. 查询所有课程成绩大于80分的同学的学号(分组和聚合函数) +select stu_id + from tb_record + group by stu_id +having min(score) > 80; + +-- Error Code: 1242. Subquery returns more than 1 row +select stu_id + , stu_name + from tb_student + where stu_id in (select stu_id + from tb_record + group by stu_id + having min(score) > 80); + +-- 35. 查询年龄最大的学生的姓名(嵌套查询) +-- 嵌套查询/子查询:把一个查询的结果作为另外一个查询的一部分来使用 +select @a := min(stu_birth) + from tb_student; + +select stu_name + from tb_student + where stu_birth = @a; + +select stu_name + from tb_student + where stu_birth = (select min(stu_birth) + from tb_student); + +-- 36. 查询选了两门以上的课程的学生姓名(嵌套查询/分组/数据筛选) +select stu_name + from tb_student + where stu_id in (select stu_id + from tb_record + group by stu_id + having count(*) > 2); + +-- 37. 查询学生的姓名、生日和所在学院名称(连接查询) +select stu_name + , stu_birth + , col_name + from tb_student, tb_college + where tb_student.col_id = tb_college.col_id; + +select stu_name + , stu_birth + , col_name + from tb_student inner join tb_college + on tb_student.col_id = tb_college.col_id; + +select stu_name + , stu_birth + , col_name + from tb_student natural join tb_college; + +-- 38. 查询学生姓名、课程名称以及成绩(连接查询) +select stu_name + , cou_name + , score + from tb_student, tb_course, tb_record + where tb_student.stu_id = tb_record.stu_id + and tb_course.cou_id = tb_record.cou_id + and score is not null; + +select stu_name + , cou_name + , score + from tb_student + inner join tb_record + on tb_student.stu_id = tb_record.stu_id + inner join tb_course + on tb_course.cou_id = tb_record.cou_id + where score is not null; --- 方法二: -select avg(coalesce(score, 0)) - from tb_record - where stu_id = 1001; - --- 查询学号为1001的学生考试成绩的标准差(聚合函数) -select stddev_samp(score) - from tb_record - where stu_id = 1001; - --- 查询男女学生的人数 - select case stu_sex when 1 then '男' else '女' end as 性别, - count(*) as 人数 - from tb_student -group by stu_sex; - --- 查询每个学院学生人数 - select col_id as 学院编号, - count(*) as 人数 - from tb_student -group by col_id; - --- 查询每个学院男女学生人数 - select col_id as 学院编号, - case stu_sex when 1 then '男' else '女' end as 性别, - count(*) as 人数 - from tb_student -group by col_id, stu_sex; - --- 查询每个学生的学号和平均成绩 - select stu_id as 学号, - round(avg(score), 2) as 平均成绩 - from tb_record -group by stu_id; - --- 查询平均成绩大于等于90分的学生的学号和平均成绩 --- 方法一: - select stu_id as 学号, - round(avg(score), 2) as 平均成绩 - from tb_record -group by stu_id - having 平均成绩 >= 90; - --- 方法二: -select * - from ( select stu_id as 学号, - round(avg(score), 2) as 平均成绩 - from tb_record - group by stu_id) as t - where 平均成绩 >= 90; - --- 查询1111、2222、3333三门课程平均成绩大于等于90分的学生的学号和平均成绩 - select stu_id as 学号, - round(avg(score), 2) as 平均成绩 - from tb_record - where cou_id in (1111, 2222, 3333) -group by stu_id - having avg(score) >= 90; - --- 嵌套查询:把一个查询的结果作为另外一个查询的一部分来使用 -select stu_name - from tb_student - where stu_birth = (select min(stu_birth) - from tb_student); - --- 查询选了两门以上的课程的学生姓名 -select stu_name - from tb_student - where stu_id in ( select stu_id - from tb_record - group by stu_id - having count(*) > 2); - --- 查询学生的姓名、生日和所在学院名称 --- 方法一: -select stu_name, - stu_birth, - col_name - from tb_student, tb_college - where tb_student.col_id = tb_college.col_id; - --- 方法二: -select stu_name, - stu_birth, - col_name - from tb_student inner join tb_college - on tb_student.col_id = tb_college.col_id; - --- 方法三: -select stu_name, - stu_birth, - col_name - from tb_student natural join tb_college; - --- 查询学生姓名、课程名称以及成绩 --- 方法一: -select stu_name, - cou_name, - score - from tb_student, tb_course, tb_record - where tb_student.stu_id = tb_record.stu_id - and tb_course.cou_id = tb_record.cou_id - and score is not null; - --- 方法二: -select stu_name, - cou_name, - score - from tb_student inner join tb_record inner join tb_course - on tb_student.stu_id = tb_record.stu_id - and tb_course.cou_id = tb_record.cou_id - where score is not null; +select stu_name + , cou_name + , score + from tb_student + natural join tb_record + natural join tb_course + where score is not null; --- 方法三: -select stu_name, - cou_name, - score - from tb_student natural join tb_record natural join tb_course - where score is not null; - --- 补充:上面的查询结果取前5条数据 - select stu_name, - cou_name, - score - from tb_student natural join tb_record natural join tb_course - where score is not null -order by stu_id asc, score desc - limit 5; - --- 补充:上面的查询结果取第6-10条数据 - select stu_name, - cou_name, - score - from tb_student inner join tb_record inner join tb_course - on tb_student.stu_id = tb_record.stu_id - and tb_course.cou_id = tb_record.cou_id -order by stu_id asc, score desc - limit 5 - offset 5; - --- 补充:上面的查询结果取第11-15条数据 - select stu_name, - cou_name, - score - from tb_student natural join tb_record natural join tb_course - where score is not null -order by stu_id asc, score desc - limit 5 - offset 10; - --- 查询选课学生的姓名和平均成绩 -select stu_name, - avg_score - from tb_student t1 inner join ( select stu_id, - round(avg(score), 2) as avg_score - from tb_record - group by stu_id) t2 - on t1.stu_id = t2.stu_id; - --- 查询学生的姓名和选课的数量 -select stu_name, - total - from tb_student t1 natural join ( select stu_id, - count(*) as total - from tb_record - group by stu_id) t2; - --- 查询每个学生的姓名和选课数量(左外连接和子查询) -select stu_name as 姓名, - coalesce (total, 0) as 选课数量 - from tb_student t1 left join ( select stu_id, - count(*) as total - from tb_record - group by stu_id) t2 - on t1.stu_id = t2.stu_id; +-- 39. 上面的查询结果按课程和成绩排序取前5条数据(分页查询) +select stu_name + , cou_name + , score + from tb_student + natural join tb_record + natural join tb_course + where score is not null + order by cou_id asc, score desc + limit 5; + +-- 40. 上面的查询结果按课程和成绩排序取第6-10条数据(分页查询) +select stu_name + , cou_name + , score + from tb_student + natural join tb_record + natural join tb_course + where score is not null + order by cou_id asc, score desc + limit 5 +offset 5; + +-- 41. 上面的查询结果按课程和成绩排序取第11-15条数据(分页查询) +select stu_name + , cou_name + , score + from tb_student + natural join tb_record + natural join tb_course + where score is not null + order by cou_id asc, score desc + limit 5 +offset 10; + +-- 42. 查询选课学生的姓名和平均成绩(嵌套查询和连接查询) +select stu_name + , avg_score + from tb_student + natural join (select stu_id + , avg(score) as avg_score + from tb_record + group by stu_id) as tmp; + +-- 43. 查询学生的姓名和选课的数量(嵌套查询和连接查询) +select stu_name + , total + from tb_student + inner join (select stu_id + , count(*) as total + from tb_record + group by stu_id) as tmp + on tb_student.stu_id = tmp.stu_id; + +-- 44. 查询所有学生的姓名和选课数量(左外连接和嵌套查询) +-- 左外连接:把左表(写在join左边的表)所有的数据都拿到,不满足连表条件的地方填充null - left outer join +-- 右外连接:把右表(写在join右边的表)所有的数据都拿到,不满足连表条件的地方填充null - right outer join +-- 全外连接:把左表和右表的数据全部拿到即便它们不满足连表条件,MySQL不支持全外连接 - full outer join +select stu_name + , coalesce(total, 0) as total + from tb_student + left join (select stu_id + , count(*) as total + from tb_record + group by stu_id) as tmp + on tb_student.stu_id = tmp.stu_id; + +-- 45. 查询没有选课的学生的姓名(左外连接和数据筛选) +select stu_name + from tb_student + left join tb_record + on tb_student.stu_id = tb_record.stu_id + where tb_record.stu_id is null; ``` 上面的 DQL 有几个地方需要加以说明: diff --git "a/\347\254\25444\350\257\276.SQL\350\257\246\350\247\243\344\271\213DCL.md" "b/\347\254\25444\350\257\276.SQL\350\257\246\350\247\243\344\271\213DCL.md" old mode 100644 new mode 100755 index e3bb186..9c797aa --- "a/\347\254\25444\350\257\276.SQL\350\257\246\350\247\243\344\271\213DCL.md" +++ "b/\347\254\25444\350\257\276.SQL\350\257\246\350\247\243\344\271\213DCL.md" @@ -1,4 +1,4 @@ -## SQL详解之DCL +## 第44课:SQL详解之DCL 数据库服务器通常包含了非常重要的数据,可以通过访问控制来确保这些数据的安全,而 DCL 就是解决这一问题的,它可以为指定的用户授予访问权限或者从指定用户处召回指定的权限。DCL 对数据库管理员来说非常重要,因为用户权限的管理关系到数据库的安全。简单的说,我们可以通过 DCL 允许受信任的用户访问数据库,阻止不受信任的用户访问数据库,同时还可以通过 DCL 将每个访问者的的权限最小化(让访问者的权限刚刚够用)。 diff --git "a/\347\254\25445\350\257\276.\347\264\242\345\274\225.md" "b/\347\254\25445\350\257\276.\347\264\242\345\274\225.md" old mode 100644 new mode 100755 index 7691a55..85fed90 --- "a/\347\254\25445\350\257\276.\347\264\242\345\274\225.md" +++ "b/\347\254\25445\350\257\276.\347\264\242\345\274\225.md" @@ -1,6 +1,6 @@ -## 索引 +## 第45课:索引 -索引是关系型数据库中用来提升查询性能最为重要的手段。关系型数据库中的索引就像一本书的目录,我们可以想象一下,如果要从一本书中找出某个知识点,但是这本书没有目录,这将是意见多么可怕的事情!我们估计得一篇一篇的翻下去,才能确定这个知识点到底在什么位置。创建索引虽然会带来存储空间上的开销,就像一本书的目录会占用一部分篇幅一样,但是在牺牲空间后换来的查询时间的减少也是非常显著的。 +索引是关系型数据库中用来提升查询性能最为重要的手段。关系型数据库中的索引就像一本书的目录,我们可以想象一下,如果要从一本书中找出某个知识点,但是这本书没有目录,这将是一件多么可怕的事情!我们估计得一篇一篇的翻下去,才能确定这个知识点到底在什么位置。创建索引虽然会带来存储空间上的开销,就像一本书的目录会占用一部分篇幅一样,但是在牺牲空间后换来的查询时间的减少也是非常显著的。 MySQL 数据库中所有数据类型的列都可以被索引。对于MySQL 8.0 版本的 InnoDB 存储引擎来说,它支持三种类型的索引,分别是 B+ 树索引、全文索引和 R 树索引。这里,我们只介绍使用得最为广泛的 B+ 树索引。使用 B+ 树的原因非常简单,因为它是目前在基于磁盘进行海量数据存储和排序上最有效率的数据结构。B+ 树是一棵[平衡树](https://zh.wikipedia.org/zh-cn/%E5%B9%B3%E8%A1%A1%E6%A0%91),树的高度通常为3或4,但是却可以保存从百万级到十亿级的数据,而从这些数据里面查询一条数据,只需要3次或4次 I/O 操作。 diff --git "a/\347\254\25446\350\257\276.\350\247\206\345\233\276+\345\207\275\346\225\260+\350\277\207\347\250\213.md" "b/\347\254\25446\350\257\276.\350\247\206\345\233\276+\345\207\275\346\225\260+\350\277\207\347\250\213.md" old mode 100644 new mode 100755 index 1c45b2d..8a48074 --- "a/\347\254\25446\350\257\276.\350\247\206\345\233\276+\345\207\275\346\225\260+\350\277\207\347\250\213.md" +++ "b/\347\254\25446\350\257\276.\350\247\206\345\233\276+\345\207\275\346\225\260+\350\277\207\347\250\213.md" @@ -1,4 +1,4 @@ -## 视图、函数和过程 +## 第46课:视图、函数和过程 为了讲解视图、函数和过程,我们首先用下面的 DDL 和 DML 创建名为 hrs 的数据库并为其二维表添加如下所示的数据。 @@ -329,7 +329,7 @@ drop procedure if exists sp_upgrade_salary; ANSI/ISO SQL 92标准定义了4个等级的事务隔离级别,如下表所示。需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定到底使用哪种事务隔离级别,这个地方没有万能的原则。 - + ### 总结 diff --git "a/\347\254\25447\350\257\276.MySQL\346\226\260\347\211\271\346\200\247.md" "b/\347\254\25447\350\257\276.MySQL\346\226\260\347\211\271\346\200\247.md" old mode 100644 new mode 100755 index 38c05c5..1a19c2f --- "a/\347\254\25447\350\257\276.MySQL\346\226\260\347\211\271\346\200\247.md" +++ "b/\347\254\25447\350\257\276.MySQL\346\226\260\347\211\271\346\200\247.md" @@ -1,4 +1,4 @@ -## MySQL 新特性 +## 第47课:MySQL 新特性 #### JSON类型 @@ -159,14 +159,14 @@ select * from ( ) `temp` where `rank` between 4 and 6; ``` -> **说明**:上面使用的函数`row_number()`可以为每条记录生成一个行号,在实际工作中可以根据需要将其替换为`rank()`或`dense_rank()`函数,三者的区别可以参考官方文档或阅读[《通俗易懂的学会:SQL窗口函数》](https://zhuanlan.zhihu.com/p/92654574)进行了解。在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。 -> -> ```SQL -> select `rank`, `ename`, `sal` from ( -> select @a:=@a+1 as `rank`, `ename`, `sal` -> from `tb_emp`, (select @a:=0) as t1 order by `sal` desc -> ) as `temp` where `rank` between 4 and 6; -> ``` +上面使用的函数`row_number()`可以为每条记录生成一个行号,在实际工作中可以根据需要将其替换为`rank()`或`dense_rank()`函数,三者的区别可以参考官方文档或阅读[《通俗易懂的学会:SQL窗口函数》](https://zhuanlan.zhihu.com/p/92654574)进行了解。在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。 + + ```SQL +select `rank`, `ename`, `sal` from ( + select @a:=@a+1 as `rank`, `ename`, `sal` + from `tb_emp`, (select @a:=0) as t1 order by `sal` desc +) as `temp` where `rank` between 4 and 6; + ``` 例子2:查询每个部门月薪最高的两名的员工的姓名和部门名称。 @@ -180,13 +180,13 @@ from ( ) as `temp` natural join `tb_dept` where `rank`<=2; ``` -> 说明:在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。 -> -> ```SQL -> select `ename`, `sal`, `dname` from `tb_emp` as `t1` +说明:在MySQL 8以前的版本,我们可以通过下面的方式来完成类似的操作。 + +```SQL +select `ename`, `sal`, `dname` from `tb_emp` as `t1` natural join `tb_dept` where ( - select count(*) from `tb_emp` as `t2` - where `t1`.`dno`=`t2`.`dno` and `t2`.`sal`>`t1`.`sal` + select count(*) from `tb_emp` as `t2` + where `t1`.`dno`=`t2`.`dno` and `t2`.`sal`>`t1`.`sal` )<2 order by `dno` asc, `sal` desc; -> ``` +``` \ No newline at end of file diff --git "a/\347\254\25448\350\257\276.Python\347\250\213\345\272\217\346\216\245\345\205\245MySQL\346\225\260\346\215\256\345\272\223.md" "b/\347\254\25448\350\257\276.Python\347\250\213\345\272\217\346\216\245\345\205\245MySQL\346\225\260\346\215\256\345\272\223.md" old mode 100644 new mode 100755 index 24f1fbc..504d8a8 --- "a/\347\254\25448\350\257\276.Python\347\250\213\345\272\217\346\216\245\345\205\245MySQL\346\225\260\346\215\256\345\272\223.md" +++ "b/\347\254\25448\350\257\276.Python\347\250\213\345\272\217\346\216\245\345\205\245MySQL\346\225\260\346\215\256\345\272\223.md" @@ -1,4 +1,4 @@ -## Python程序接入MySQL数据库 +## 第48课:Python程序接入MySQL数据库 在 Python3 中,我们可以使用`mysqlclient`或者`pymysql`三方库来接入 MySQL 数据库并实现数据持久化操作。二者的用法完全相同,只是导入的模块名不一样。我们推荐大家使用纯 Python 的三方库`pymysql`,因为它更容易安装成功。下面我们仍然以之前创建的名为`hrs`的数据库为例,为大家演示如何通过 Python 程序操作 MySQL 数据库实现数据持久化操作。