Procházet zdrojové kódy

更新了部分代码

jackfrued před 7 roky
rodič
revize
161af9c84d

+ 628 - 4
Day16-20/Python语言进阶.md

@@ -1,20 +1,644 @@
 ## Python语言进阶
 
-### 常用数据结构
+### 数据结构和算法
 
+#### 排序算法(冒泡和归并)
 
+```Python
+def bubble_sort(items, comp=lambda x, y: x > y):
+    """高质量冒泡排序(搅拌排序)"""
+    for i in range(len(items) - 1):
+        swapped = False
+        for j in range(len(items) - 1 - i):
+            if comp(items[j], items[j + 1]):
+                items[j], items[j + 1] = items[j + 1], items[j]
+                swapped = True
+        if swapped:
+            swapped = False
+            for j in range(len(items) - 2 - i, i, -1):
+                if comp(items[j - 1], items[j]):
+                    items[j], items[j - 1] = items[j - 1], items[j]
+                    swapped = True
+        if not swapped:
+            break
+```
 
-### 函数的高级用法
+```Python
+def merge_sort(items, comp=lambda x, y: x <= y):
+    """归并排序(分治法)"""
+    if len(items) < 2:
+        return items[:]
+    mid = len(items) // 2
+    left = merge_sort(items[:mid], comp)
+    right = merge_sort(items[mid:], comp)
+    return merge(left, right, comp)
 
 
+def merge(items1, items2, comp=lambda x, y: x <= y):
+    """合并(将两个有序的列表合并成一个有序的列表)"""
+    items = []
+    idx1, idx2 = 0, 0
+    while idx1 < len(items1) and idx2 < len(items2):
+        if comp(items1[idx1], items2[idx2]):
+            items.append(items1[idx1])
+            idx1 += 1
+        else:
+            items.append(items2[idx2])
+            idx2 += 1
+    items += items1[idx1:]
+    items += items2[idx2:]
+    return items
+```
 
-### 面向对象高级知识
+```Python
+def seq_search(items, key):
+    """顺序查找"""
+    for index, item in enumerate(items):
+        if item == key:
+            return index
+    return -1
+```
+#### 查找算法(顺序和折半)
 
+```Python
+def bin_search(items, key):
+    """折半查找(循环实现)"""
+    start, end = 0, len(items) - 1
+    while start <= end:
+        mid = (start + end) // 2
+        if key > items[mid]:
+            start = mid + 1
+        elif key < items[mid]:
+            end = mid - 1
+        else:
+            return mid
+    return -1
+```
 
+#### 使用生成式(推导式)
+
+```Python
+prices = {
+    'AAPL': 191.88,
+    'GOOG': 1186.96,
+    'IBM': 149.24,
+    'ORCL': 48.44,
+    'ACN': 166.89,
+    'FB': 208.09,
+    'SYMC': 21.29
+}
+# 用股票价格大于100元的股票构造一个新的字典
+prices2 = {key: value for key, value in prices.items() if value > 100}
+print(prices2)
+```
+
+#### 嵌套的列表
+
+```Python
+def main():
+    names = ['关羽', '张飞', '赵云', '马超', '黄忠']
+    courses = ['语文', '数学', '英语']
+    # 录入五个学生三门课程的成绩
+    # 错误 - 参考http://pythontutor.com/visualize.html#mode=edit
+    # scores = [[None] * len(courses)] * len(names)
+    scores = [[None] * len(courses) for _ in range(len(names))]
+    for row, name in enumerate(names):
+        for col, course in enumerate(courses):
+            scores[row][col] = float(input(f'请输入{name}的{course}成绩: '))
+    print(scores)
+
+
+if __name__ == '__main__':
+    main()
+```
+
+[Python Tutor](http://pythontutor.com/) - VISUALIZE CODE AND GET LIVE HELP
+
+#### heapq、itertools等的用法
+
+```Python
+"""
+从列表中找出最大的或最小的N个元素
+"""
+import heapq
+
+
+def main():
+    list1 = [34, 25, 12, 99, 87, 63, 58, 78, 88, 92]
+    list2 = [
+        {'name': 'IBM', 'shares': 100, 'price': 91.1},
+        {'name': 'AAPL', 'shares': 50, 'price': 543.22},
+        {'name': 'FB', 'shares': 200, 'price': 21.09},
+        {'name': 'HPQ', 'shares': 35, 'price': 31.75},
+        {'name': 'YHOO', 'shares': 45, 'price': 16.35},
+        {'name': 'ACME', 'shares': 75, 'price': 115.65}
+    ]
+    print(heapq.nlargest(3, list1))
+    print(heapq.nsmallest(3, list1))
+    print(heapq.nlargest(2, list2, key=lambda x: x['price']))
+    print(heapq.nlargest(2, list2, key=lambda x: x['shares']))
+
+
+if __name__ == '__main__':
+    main()
+```
+
+```Python
+"""
+排列 / 组合 / 笛卡尔积
+"""
+import itertools
+
+
+def main():
+    for val in itertools.permutations('ABCD'):
+        print(val)
+    print('-' * 50)
+    for val in itertools.combinations('ABCDE', 3):
+        print(val)
+    print('-' * 50)
+    for val in itertools.product('ABCD', '123'):
+        print(val)
+
+
+if __name__ == '__main__':
+    main()
+```
+
+#### collections模块下的工具类
+
+```Python
+"""
+找出序列中出现次数最多的元素
+"""
+from collections import Counter
+
+
+def main():
+    words = [
+        'look', 'into', 'my', 'eyes', 'look', 'into', 'my', 'eyes',
+        'the', 'eyes', 'the', 'eyes', 'the', 'eyes', 'not', 'around',
+        'the', 'eyes', "don't", 'look', 'around', 'the', 'eyes',
+        'look', 'into', 'my', 'eyes', "you're", 'under'
+    ]
+    counter = Counter(words)
+    print(counter.most_common(3))
+
+
+if __name__ == '__main__':
+    main()
+```
+
+#### 穷举法、贪婪法、分治法、动态规划
+
+```Python
+"""
+穷举法 - 穷尽所有可能直到找到正确答案
+"""
+
+
+def main():
+    # 公鸡5元一只 母鸡3元一只 小鸡1元三只
+    # 用100元买100只鸡 问公鸡/母鸡/小鸡各多少只
+    for x in range(20):
+        for y in range(33):
+            z = 100 - x - y
+            if 5 * x + 3 * y + z // 3 == 100 and z % 3 == 0:
+                print(x, y, z)
+    # A、B、C、D、E五人在某天夜里合伙捕鱼 最后疲惫不堪各自睡觉
+    # 第二天A第一个醒来 他将鱼分为5份 扔掉多余的1条 拿走自己的一份
+    # B第二个醒来 也将鱼分为5份 扔掉多余的1条 拿走自己的一份
+    # 然后C、D、E依次醒来也按同样的方式分鱼 问他们至少捕了多少条鱼
+    fish = 1
+    while True:
+        total = fish
+        enough = True
+        for _ in range(5):
+            if (total - 1) % 5 == 0:
+                total = (total - 1) // 5 * 4
+            else:
+                enough = False
+                break
+        if enough:
+            print(fish)
+            break
+        fish += 1
+
+
+if __name__ == '__main__':
+    main()
+```
+
+```Python
+"""
+动态规划 - 适用于有重叠子问题和最优子结构性质的问题
+使用动态规划方法所耗时间往往远少于朴素解法(用空间换取时间)
+"""
+
+
+def fib(num, temp={}):
+    """用递归计算Fibonacci数"""
+    if num in (1, 2):
+        return 1
+    try:
+        return temp[num]
+    except KeyError:
+        temp[num] = fib(num - 1) + fib(num - 2)
+        return temp[num]
+```
+
+### 函数的使用方式
+
+- 将函数视为“一等公民”
+
+- 高阶函数的用法(filter、map以及它们的替代品)
+
+- 位置参数、可变参数、关键字参数、命名关键字参数
+
+- 参数的元信息(代码可读性问题)
+
+- 匿名函数和内联函数的用法(lambda函数)
+
+- 闭包和作用域问题(LEGB)
+
+- 装饰器函数(使用装饰器和取消装饰器)
+
+  输出函数执行时间的装饰器。
+
+  ```Python
+  from functools import wraps
+  from time import time
+  
+  
+  def record(output):
+  	
+  	def decorate(func):
+  		
+  		@wraps(func)
+  		def wrapper(*args, **kwargs):
+  			start = time()
+  			result = func(*args, **kwargs)
+  			output(func.__name__, time() - start)
+  			return result
+              
+  		return wrapper
+  	
+  	return decorate
+  ```
+
+  ```Python
+  from functools import wraps
+  from time import time
+  
+  
+  class Record(object):
+  
+      def __init__(self, output):
+          self.output = output
+  
+      def __call__(self, func):
+  
+          @wraps(func)
+          def wrapper(*args, **kwargs):
+              start = time()
+              result = func(*args, **kwargs)
+              self.output(func.__name__, time() - start)
+              return result
+  
+          return wrapper
+  ```
+
+  用装饰器来实现单例模式。
+
+  ```Python
+  from functools import wraps
+  
+  
+  def singleton(cls):
+      instances = {}
+  
+      @wraps(cls)
+      def wrapper(*args, **kwargs):
+          if cls not in instances:
+              instances[cls] = cls(*args, **kwargs)
+          return instances[cls]
+  
+      return wrapper
+  
+  
+  @singleton
+  class Singleton(object):
+      pass
+  ```
+
+### 面向对象相关知识
+
+- 三大支柱:封装、继承、多态
+
+  ```Python
+  """
+  月薪结算系统
+  部门经理每月15000 程序员每小时200 销售员1800底薪+销售额5%提成
+  """
+  from abc import ABCMeta, abstractmethod
+  
+  
+  class Employee(metaclass=ABCMeta):
+      """员工(抽象类)"""
+  
+      def __init__(self, name):
+          self._name = name
+  
+      @property
+      def name(self):
+          """姓名"""
+          return self._name
+  
+      @abstractmethod
+      def get_salary(self):
+          """结算月薪(抽象方法)"""
+          pass
+  
+  
+  class Manager(Employee):
+      """部门经理"""
+  
+      def get_salary(self):
+          return 15000.0
+  
+  
+  class Programmer(Employee):
+      """程序员"""
+  
+      def __init__(self, name):
+          self._working_hour = 0
+          super().__init__(name)
+  
+      @property
+      def working_hour(self):
+          """工作时间"""
+          return self._working_hour
+  
+      @working_hour.setter
+      def working_hour(self, hour):
+          self._working_hour = hour if hour > 0 else 0
+  
+      def get_salary(self):
+          return 200.0 * self.working_hour
+  
+  
+  class Salesman(Employee):
+      """销售员"""
+  
+      def __init__(self, name):
+          self._sales = 0.0
+          super().__init__(name)
+  
+      @property
+      def sales(self):
+          return self._sales
+  
+      @sales.setter
+      def sales(self, sales):
+          self._sales = sales if sales > 0 else 0
+  
+      def get_salary(self):
+          return 1800.0 + self.sales * 0.05
+  
+  
+  def main():
+      emps = [
+          Manager('刘备'), Manager('曹操'), Programmer('许褚'),
+          Salesman('貂蝉'), Salesman('赵云'), Programmer('张辽'),
+          Programmer('关羽'), Programmer('周瑜')
+      ]
+      for emp in emps:
+          if isinstance(emp, Programmer):
+              emp.working_hour = int(input('本月工作时间: '))
+          elif isinstance(emp, Salesman):
+              emp.sales = float(input('本月销售额: '))
+          print('%s: %.2f元' % (emp.name, emp.get_salary()))
+  
+  
+  if __name__ == '__main__':
+      main()
+  ```
+
+- 对象的复制(深复制/深拷贝/深度克隆和浅复制/浅拷贝/影子克隆)
+
+- 垃圾回收、循环引用和弱引用
+
+  Python使用了自动化内存管理,这种管理机制以**引用计数**为基础,同时也引入了**标记-清除**和**分代收集**两种机制为辅的策略。
+
+  ```C
+  typedef struct_object {
+      /* 引用计数 */
+      int ob_refcnt;
+      /* 对象指针 */
+      struct_typeobject *ob_type;
+  } PyObject;
+  ```
+
+  ```C
+  /* 增加引用计数的宏定义 */
+  #define Py_INCREF(op)   ((op)->ob_refcnt++)
+  /* 减少引用计数的宏定义 */
+  #define Py_DECREF(op) \ //减少计数
+      if (--(op)->ob_refcnt != 0) \
+          ; \
+      else \
+          __Py_Dealloc((PyObject *)(op))
+  ```
+
+  导致引用计数+1的情况:
+
+  - 对象被创建,例如`a = 23`
+  - 对象被引用,例如`b = a`
+  - 对象被作为参数,传入到一个函数中,例如`f(a)`
+  - 对象作为一个元素,存储在容器中,例如`list1 = [a, a]`
+
+  导致引用计数-1的情况:
+
+  - 对象的别名被显式销毁,例如`del a`
+  - 对象的别名被赋予新的对象,例如`a = 24`
+  - 一个对象离开它的作用域,例如f函数执行完毕时,f函数中的局部变量(全局变量不会)
+  - 对象所在的容器被销毁,或从容器中删除对象
+
+  引用计数可能会导致循环引用问题,而循环引用会导致内存泄露,如下面的代码所示。为了解决这个问题,Python中引入了“标记-清除”和“分代收集”。在创建一个对象的时候,对象被放在第一代中,如果在第一代的垃圾检查中对象存活了下来,该对象就会被放到第二代中,同理在第二代的垃圾检查中对象存活下来,该对象就会被放到第三代中。
+
+  ```Python
+  list1 = []
+  list2 = []
+  list1.append(list2)
+  list2.append(list1)
+  ```
+
+  以下情况会导致垃圾回收:
+
+  - 调用`gc.collect()`
+  - gc模块的计数器达到阀值
+  - 程序退出
+
+  如果循环引用中两个对象都定义了`__del__`方法,gc模块不会销毁这些不可达对象,因为gc模块不知道应该先调用哪个对象的`__del__`方法,这个问题在Python 3.6中得到了解决。
+
+  也可以通过`weakref`模块构造弱引用的方式来解决循环引用的问题。
+
+- 魔法属性和方法(请参考《Python魔法方法指南》)
+
+  有几个小问题请大家思考:
+
+  - 自定义的对象能不能使用运算符做运算?
+  - 自定义的对象能不能放到set中?能去重吗?
+  - 自定义的对象能不能作为dict的键?
+  - 自定义的对象能不能使用上下文语法?
+
+- 混入(Mixin)
+
+  ```Python
+  """
+  限制字典只有在指定的key不存在时才能设置键值对
+  MRO - Method Resolution Order - 多重继承时的方法解析顺序
+  """
+  
+  
+  class SetOnceMappingMixin:
+      __slots__ = ()
+  
+      def __setitem__(self, key, value):
+          if key in self:
+              raise KeyError(str(key) + ' already set')
+          return super().__setitem__(key, value)
+  
+  
+  class SetOnceDict(SetOnceMappingMixin, dict):
+      pass
+  
+  
+  def main():
+      dict1 = SetOnceDict()
+      try:
+          dict1['username'] = 'jackfrued'
+          dict1['username'] = 'hellokitty'
+          dict1['username'] = 'wangdachui'
+      except KeyError:
+          pass
+      print(dict1)
+  
+  
+  if __name__ == '__main__':
+      main()
+  ```
+
+- 元编程和元类
+
+  用元类实现单例模式。
+
+  ```Python
+  """
+  通过元类实现单例模式
+  """
+  
+  
+  class SingletonMeta(type):
+      """单例的元类"""
+  
+      def __init__(cls, *args, **kwargs):
+          cls.__instance = None
+          super().__init__(*args, **kwargs)
+  
+      def __call__(cls, *args, **kwargs):
+          if cls.__instance is None:
+              cls.__instance = super().__call__(*args, **kwargs)
+          return cls.__instance
+  
+  
+  class Singleton(metaclass=SingletonMeta):
+      """单例类"""
+  
+      def __init__(self, name):
+          self._name = name
+          from random import randrange
+          self._value = randrange(100000)
+  
+      @property
+      def name(self):
+          return self._name
+  
+      @property
+      def value(self):
+          return self._value
+  
+  
+  def main():
+      sin1 = Singleton('Lee')
+      sin2 = Singleton('Wang')
+      print(sin1 == sin2)
+      print(sin1.value, sin2.value)
+      print(sin1.name, sin2.name)
+  
+  
+  if __name__ == '__main__':
+      main()
+  ```
 
 ### 迭代器和生成器
 
+```Python
+"""
+生成器和迭代器
+"""
+
+
+def fib1(num):
+    """普通函数"""
+    a, b = 0, 1
+    for _ in range(num):
+        a, b = b, a + b
+    return a
+
+
+def fib2(num):
+    """生成器"""
+    a, b = 0, 1
+    for _ in range(num):
+        a, b = b, a + b
+        yield a
+
+
+class Fib3:
+    """迭代器"""
+
+    def __init__(self, num):
+        self.num = num
+        self.a, self.b = 0, 1
+        self.idx = 0
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self.idx < self.num:
+            self.a, self.b = self.b, self.a + self.b
+            self.idx += 1
+            return self.a
+        raise StopIteration()
+
+
+def main():
+    for val in fib2(20):
+        print(val)
+    print('-' * 50)
+    for val in Fib3(20):
+        print(val)
+
+
+if __name__ == '__main__':
+    main()
+```
 
+### 并发编程
 
-### 并发和异步编程
+- 多线程和多进程
+- 协程和异步I/O
+- concurrent.futures
 

+ 25 - 0
Day16-20/code/example01.py

@@ -0,0 +1,25 @@
+"""
+实现查找功能的模块
+"""
+
+
+def seq_search(items, elem):
+    """顺序查找"""
+    for index, item in enumerate(items):
+        if item == elem:
+            return index
+    return -1
+
+
+def bin_search(items, elem):
+    """折半查找(二分查找)"""
+    start, end = 0, len(items) - 1
+    while start <= end:
+        mid = (start + end) // 2
+        if elem < items[mid]:
+            end = mid - 1
+        elif elem > items[mid]:
+            start = mid + 1
+        else:
+            return mid
+    return -1

+ 113 - 0
Day16-20/code/example02.py

@@ -0,0 +1,113 @@
+"""
+排序 - 冒泡排序(简单O(N**2)) / 归并排序(高级O(N*log2N))
+冒泡排序
+34, 99, 52, 11, 47, 68, 50, 84
+34, 52, 11, 47, 68, 50, 84, 99
+34, 11, 47, 52, 50, 68, 84
+11, 34, 47, 50, 52, 68
+
+快速排序
+34, 99, 52, 11, 47, 68, 50, 84
+{34, 11, 47}, {50}, {99, 52, 68, 84}
+{11}, {34}, {47}, {50}, {52, 68, 84}, {99}
+{11}, {34}, {47}, {50}, {52}, {68, 84}, {99}
+{11}, {34}, {47}, {50}, {52}, {68}, {84}, {99}
+
+归并排序 - 分治法(divide-and-conquer)
+34, 99, 52, 11, 47, 68, 50, 84
+{34, 99, 52, 11}, {47, 68, 50, 84}
+{34, 99}, {52, 11}, {47, 68}, {50, 84}
+{34}, {99}, {52}, {11}, {47}, {68}, {50}, {84}
+{34, 99}, {11, 52}, {47, 68}, {50, 84}
+{11, 34, 52, 99}, {47, 50, 68, 84}
+{11, 34, 47, 50, 52, 68, 84, 99}
+
+在使用分治法的时候通常都会使用到递归调用这种编程手段
+一个函数直接或间接的调用了自身就称之为递归调用
+"""
+
+
+# 9 1 2 3 4 5 6 7 8
+# 2 3 4 5 6 7 8 9 1
+# *前面的参数称为位置参数, *后面的参数称为命名关键字参数
+# 所谓命名关键字参数就是调用函数时必须以"参数名=参数值"的形式传入参数
+def bubble_sort(origin_items, *, comp=lambda x, y: x > y):
+    """冒泡排序"""
+    items = origin_items[:]
+    length = len(items)
+    for i in range(1, length):
+        swapped = False
+        for j in range(0, length - i):
+            if comp(items[j], items[j + 1]):
+                items[j], items[j + 1] = items[j + 1], items[j]
+                swapped = True
+        if swapped:
+            swapped = False
+            for j in range(length - i - 1, i - 1, -1):
+                if comp(items[j - 1], items[j]):
+                    items[j - 1], items[j] = items[j], items[j - 1]
+                    swapped = True
+        if not swapped:
+            break
+    return items
+
+
+def merge(list1, list2, comp=lambda x, y: x <= y):
+    """"有序合并(将两个有序的列表合并成一个新的有序的列表)"""
+    list3 = []
+    index1, index2 = 0, 0
+    while index1 < len(list1) and index2 < len(list2):
+        if comp(list1[index1], list2[index2]):
+            list3.append(list1[index1])
+            index1 += 1
+        else:
+            list3.append(list2[index2])
+            index2 += 1
+    list3 += list1[index1:]
+    list3 += list2[index2:]
+    return list3
+
+
+def merge_sort(origin_items, comp=lambda x, y: x <= y):
+    """归并排序"""
+    if len(origin_items) <= 1:
+        return origin_items[:]
+    mid = len(origin_items) // 2
+    left = merge_sort(origin_items[:mid], comp)
+    right = merge_sort(origin_items[mid:], comp)
+    return merge(left, right, comp)
+
+
+class Person:
+    """人"""
+
+    def __init__(self, name, age):
+        self.name = name
+        self.age = age
+
+    def __repr__(self):
+        return f'{self.name}: {self.age}'
+
+
+def main():
+    # list1 = [12, 35, 48, 87, 92]
+    # list2 = [39, 44, 50, 60, 77, 88]
+    # list3 = merge(list1, list2)
+    # print(list3)
+    items = [34, 99, 52, 11, 47, 50, 84]
+    print(items)
+    print(merge_sort(items))
+    # items = ['hi', 'hello', 'orange', 'watermelon', 'zoo', 'pitaya']
+    # items = [
+    #     Person("LuoHao", 38), Person("Baiyuanfang", 25),
+    #     Person("Zhangsanfeng", 120), Person("Lee", 18)
+    # ]
+    # new_items = bubble_sort(items, comp=lambda x, y: len(x) > len(y))
+    # new_items = bubble_sort(items, comp=lambda x, y: x.age > y.age)
+    # print(items)
+    # print(new_items)
+
+
+if __name__ == '__main__':
+    main()
+

+ 44 - 0
Day16-20/code/example03.py

@@ -0,0 +1,44 @@
+"""
+递归(recursion)
+"""
+
+
+def fac(num):
+    """求阶乘"""
+    if num in (0, 1):
+        return 1
+    return num * fac(num - 1)
+
+
+# 动态规划 - 把求解问题的中间结果保存起来
+# 这种算法适合求解有最优子结构的问题或子问题会重复求解的问题
+def fib(num, temp={}):
+    """计算斐波拉切数"""
+    # 递归的两个要素
+    # 收敛条件 - 什么时候结束递归
+    if num in (1, 2):
+        return 1
+    # 递归公式 - 降低问题的求解难度
+    try:
+        return temp[num]
+    except KeyError:
+        temp[num] = fib(num - 1) + fib(num - 2)
+        return temp[num]
+
+
+def fib2(total):
+    """斐波拉切数列生成器"""
+    num1, num2 = 0, 1
+    for _ in range(total):
+        num1, num2 = num2, num1 + num2
+        yield num1
+
+
+def main():
+    """主函数"""
+    for num in fib2(120):
+        print(num)
+
+
+if __name__ == '__main__':
+    main()

+ 145 - 0
Day16-20/code/example04.py

@@ -0,0 +1,145 @@
+"""
+程序设计的范式(理念):
+1. 指令式程序设计 - 汇编语言
+2. 面向过程程序设计 - 把一组指令封装成一个过程,需要执行这组指令时调用这个过程即可 - C
+3. 面向对象程序设计 - 将数据和操作数据的函数从逻辑上组织成了对象 - C++ / Java
+4. 函数式程序设计 - 函数是一等对象(一等公民) - Haskell
+
+面向对象程序设计步骤:
+1. 定义类 - 抽象过程 - 数据抽象(静态特征-属性)/行为抽象(动态特征-方法)
+2. 创建对象 - 构造器 - 初始化(__init__)
+3. 给对象发消息 - 对象引用.对象方法(参数)
+
+面向对象的三大支柱 - 封装 / 继承 / 多态
+
+类与类(对象与对象)之间的关系:
+1. is-a: 继承
+2. has-a: 关联 / 聚合 / 合成
+3. use-a: 依赖
+
+面向对象的设计原则/SOLID原则:
+1. 单一职责原则 - 类的设计要高内聚
+2. 开闭原则 - 接受扩展不接受修改 - 抽象是关键/用继承封装可变性
+3. 依赖倒转原则 - 面向抽象编程
+4. 里氏替换原则 - 任何时候都可以使用子类型对象替换父类型对象
+5. 接口隔离原则
+6. 合成聚合复用原则 - 优先考虑用强关联而不是继承去复用代码
+7. 最少知识原则(迪米特法则) - 不要跟陌生人讲话
+
+GoF设计模式 - 23种场景(Python中有16中已经被弱化)
+- 单例、工厂、原型、适配器、观察者、策略
+"""
+from enum import Enum
+from enum import unique
+
+import random
+
+# 经验: 符号常量优于字面常量
+# 枚举类型是定义符号常量的最佳选择
+# 如果一个变量的值只有有限多个选项那么最好使用枚举
+@unique
+class Suite(Enum):
+    """花色"""
+
+    SPADE = 0
+    HEART = 1
+    CLUB = 2
+    DIAMOND = 3
+
+
+class Card():
+    """牌"""
+
+    def __init__(self, suite, face):
+        self.suite = suite
+        self.face = face
+
+    def show(self):
+        """显示牌的花色和点数"""
+        suites = ['♠️', '♥️', '♣️', '♦️']
+        faces = [
+            '', 'A', '2', '3', '4', '5', '6',
+            '7', '8', '9', '10', 'J', 'Q', 'K'
+        ]
+        return f'{suites[self.suite.value]} {faces[self.face]}'
+
+    def __str__(self):
+        return self.show()
+
+    def __repr__(self):
+        return self.show()
+
+
+class Poker():
+    """扑克"""
+
+    def __init__(self):
+        self.index = 0
+        self.cards = [Card(suite, face)
+                      for suite in Suite
+                      for face in range(1, 14)]
+
+    def shuffle(self):
+        """洗牌"""
+        random.shuffle(self.cards)
+
+    def deal(self):
+        """发牌"""
+        temp = self.cards[self.index]
+        self.index += 1
+        return temp
+
+    @property
+    def has_more(self):
+        """是否有牌可以发"""
+        return self.index < len(self.cards)
+
+
+class Player():
+    """玩家"""
+
+    def __init__(self, name):
+        self.name = name
+        self.cards = []
+
+    def get_one(self, card):
+        """摸一张牌"""
+        self.cards.append(card)
+
+    def drop_one(self, index):
+        """打出一张牌"""
+        return self.cards.remove(index)
+
+    def get_many(self, more_cards):
+        """摸多张牌"""
+        self.cards += more_cards
+
+    def drop_cards(self):
+        """扔掉所有牌"""
+        self.cards.clear()
+
+    def arrange(self):
+        """整理手上的牌"""
+        self.cards.sort(key=lambda x: (x.suite.value, x.face))
+
+
+def main():
+    """主函数"""
+    poker = Poker()
+    poker.shuffle()
+    players = [
+        Player("东邪"), Player("西毒"),
+        Player("南帝"), Player("北丐")
+    ]
+    for _ in range(3):
+        for player in players:
+            if poker.has_more:
+                player.get_one(poker.deal())
+    for player in players:
+        player.arrange()
+        print(player.name)
+        print(player.cards)
+
+
+if __name__ == '__main__':
+    main()

+ 47 - 0
Day16-20/code/example05.py

@@ -0,0 +1,47 @@
+"""
+设计模式 - 策略模式(指定的策略不同执行的算法不同)
+"""
+from hashlib import md5
+from hashlib import sha1
+from hashlib import sha256
+from hashlib import sha512
+
+
+class StreamHasher():
+    """哈希摘要生成器"""
+
+    def __init__(self, algorithm='md5', size=1024):
+        self.size = size
+        alg = algorithm.lower()
+        if alg == 'md5':
+            self.hasher = md5()
+        elif alg == 'sha1':
+            self.hasher = sha1()
+        elif alg == 'sha256':
+            self.hasher = sha256()
+        elif alg == 'sha512':
+            self.hasher = sha512()
+        else:
+            raise ValueError('不支持指定的摘要算法')
+
+    # 魔法方法: 让对象可以像函数一样被调用
+    def __call__(self, stream):
+        return self.to_digest(stream)
+
+    def to_digest(self, stream):
+        """生成十六进制形式的哈希摘要字符串"""
+        for data in iter(lambda: stream.read(self.size), b''):
+            self.hasher.update(data)
+        return self.hasher.hexdigest()
+
+
+def main():
+    """主函数"""
+    hasher = StreamHasher('sha1', 4096)
+    with open('Python语言规范.pdf', 'rb') as stream:
+        # print(hasher.to_digest(stream))
+        print(hasher(stream))
+
+
+if __name__ == '__main__':
+    main()

+ 81 - 0
Day16-20/code/example06.py

@@ -0,0 +1,81 @@
+"""
+抽象类 / 继承 / 多态
+"""
+from abc import ABCMeta, abstractmethod
+
+
+class Employee(metaclass=ABCMeta):
+    """员工"""
+
+    def __init__(self, name):
+        self.name = name
+
+    @abstractmethod
+    def get_salary(self):
+        """结算月薪"""
+        pass
+
+
+class Manager(Employee):
+    """部门经理"""
+
+    def get_salary(self):
+        return 15000
+
+
+class Programmer(Employee):
+    """程序员"""
+
+    def __init__(self, name):
+        super().__init__(name)
+        self._working_hour = 0
+
+    @property
+    def working_hour(self):
+        return self._working_hour
+
+    @working_hour.setter
+    def working_hour(self, _working_hour):
+        self._working_hour = 0 if _working_hour < 0 \
+            else _working_hour
+
+    def get_salary(self):
+        return 200 * self.working_hour
+
+
+class Salesman(Employee):
+    """销售员"""
+
+    def __init__(self, name):
+        super().__init__(name)
+        self._sales = 0
+
+    @property
+    def sales(self):
+        return self._sales
+    
+    @sales.setter
+    def sales(self, _sales):
+        self._sales = 0 if _sales < 0 else _sales
+
+    def get_salary(self):
+        return 1800 + 0.05 * self.sales
+
+
+def main():
+    """主函数"""
+    emps = [
+        Programmer("王大锤"), Manager("武则天"),
+        Programmer("狄仁杰"), Salesman("白洁"),
+        Programmer("白元芳"), Salesman("冷面")
+    ]
+    for emp in emps:
+        if isinstance(emp, Programmer):
+            emp.working_hour = int(input(f'{emp.name}本月工作时间: '))
+        elif isinstance(emp, Salesman):
+            emp.sales = float(input(f'{emp.name}本月销售额: '))
+        print("%s本月工资为: ¥%.2f元" % (emp.name, emp.get_salary()))
+
+
+if __name__ == '__main__':
+    main()

+ 35 - 0
Day16-20/code/example07.py

@@ -0,0 +1,35 @@
+"""
+元类 - 设计模式 - 单例模式(让一个类只能创建唯一的实例)
+"""
+
+
+class SingletonMeta(type):
+    """单例类的元类(描述其他类的类)"""
+
+    def __init__(cls, *args, **kwargs):
+        cls.__instance = None
+
+    def __call__(cls, *args, **kwargs):
+        if cls.__instance is None:
+            cls.__instance = super().__call__(*args, **kwargs)
+        return cls.__instance
+
+
+class President(metaclass=SingletonMeta):
+    """总统(单例类)"""
+
+    def __init__(self, name):
+        self.name = name
+
+
+def main():
+    p1 = President("王大锤")
+    p2 = President("奥巴马")
+    print(p1.name)
+    print(p2.name)
+    print(p1 == p2)
+    print(p1 is p2)
+
+
+if __name__ == '__main__':
+    main()

+ 46 - 0
Day16-20/code/example08.py

@@ -0,0 +1,46 @@
+"""
+设计模式 - 单例模式(让一个类只能创建唯一的实例)
+"""
+from functools import wraps
+
+
+def singleton(cls):
+    instances = {}
+
+    @wraps(cls)
+    def wrapper(*args, **kwargs):
+        if cls not in instances:
+            instances[cls] = cls(*args, **kwargs)
+        return instances[cls]
+
+    return wrapper
+
+
+@singleton
+class President():
+    """总统(单例类)"""
+
+    def __init__(self, name):
+        self.name = name
+
+
+def main():
+    p1 = President("王大锤")
+    p2 = President("奥巴马")
+    print(p1.name)
+    print(p2.name)
+    print(p1 == p2)
+    print(p1 is p2)
+    print('-' * 30)
+    # 取消装饰器
+    President2 = President.__wrapped__
+    p2 = President2("奥巴马")
+    print(p1.name)
+    print(p2.name)
+    print(p1 == p2)
+    print(p1 is p2)
+
+
+
+if __name__ == '__main__':
+    main()

+ 36 - 0
Day16-20/code/example09.py

@@ -0,0 +1,36 @@
+"""
+装饰器 - 背后的设计模式是代理模式(注意不是装饰器模式)
+代理模式通常是让代理对象去执行被代理对象的行为并在这个过程中增加额外的操作
+这种设计模式最适合处理代码中的横切关注功能(与正常业务没有必然联系但是又需要执行的功能)
+"""
+from functools import wraps
+from time import time
+
+
+def record(output=print):
+    
+    def decorate(func):
+        
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            start = time()
+            result = func(*args, **kwargs)
+            output(func.__name__, time() - start)
+            return result
+            
+        return wrapper
+    
+    return decorate
+
+
+@record()
+def some_task():
+    print(123 ** 100000)
+
+
+if __name__ == '__main__':
+    some_task()
+    print(some_task.__name__)
+    # 取消装饰器
+    some_task = some_task.__wrapped__
+    some_task()

+ 40 - 0
Day16-20/code/example10.py

@@ -0,0 +1,40 @@
+"""
+混入 - Mix-in
+限制字典只有在指定的key不存在时才能设置键值对
+原则上能够不使用多重继承的地方都不要用多重继承
+MRO - Method Resolution Order - 方法解析顺序
+Python2 - 深度优先搜索
+Python3 - 类似于广度优先搜索 - C3算法
+类.__mro__ / 类.mro()
+"""
+
+
+class SetOnceMappingMixin():
+    """混入类"""
+    __slots__ = ()
+
+    def __setitem__(self, key, value):
+        if key in self:
+            raise KeyError(f'键{str(key)}已经存在')
+        return super().__setitem__(key, value)
+
+
+class SetOnceDict(SetOnceMappingMixin, dict):
+    """自定义字典"""
+    pass
+
+
+def main():
+    """主函数"""
+    dict1 = SetOnceDict()
+    try:
+        dict1['username'] = 'jackfrued'
+        dict1['username'] = 'hellokitty'
+        dict1['username'] = 'wangdachui'
+    except KeyError as error:
+        print('Error:', error)
+    print(dict1)
+
+
+if __name__ == '__main__':
+    main()

+ 36 - 0
Day16-20/code/example11.py

@@ -0,0 +1,36 @@
+"""
+自定义迭代器
+"""
+
+
+class Fibo:
+    """斐波拉切数列迭代器"""
+
+    def __init__(self, num):
+        self.num = num
+        self.a, self.b = 0, 1
+        self.idx = 0
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        if self.idx < self.num:
+            self.a, self.b = self.b, self.a + self.b
+            self.idx += 1
+            return self.a
+        raise StopIteration()
+
+
+def main():
+    """主函数"""
+    for val in Fibo(10):
+        print(val)
+    print('-' * 10)
+    fibo_iter = Fibo(10)
+    for _ in range(10):
+        print(next(fibo_iter))
+
+
+if __name__ == '__main__':
+    main()

+ 45 - 0
Day16-20/code/example12.py

@@ -0,0 +1,45 @@
+"""
+协程 - 可以通过yield来调用其它协程,yield将执行权转让给其他协程
+协程之间不是调用者与被调用者的关系,而是彼此对称平等的
+"""
+
+
+def num_generator(start, end):
+    """指定起始值的整数生成器"""
+    for num in range(start, end + 1):
+        yield num
+
+
+def square_mapper(numbers):
+    """将数值映射为其平方的协程"""
+    for num in numbers:
+        yield num ** 2
+
+
+def prime_filter(numbers):
+    """从数值中过滤出素数的协程"""
+    for num in numbers:
+        flag = True
+        for factor in range(2, int(num ** 0.5 + 1)):
+            if num % factor == 0:
+                flag = False
+                break
+        if flag:
+            yield num
+
+
+def main():
+    tasks = []
+    tasks.append(square_mapper(num_generator(1, 100)))
+    tasks.append(prime_filter(num_generator(2, 100)))
+    for _ in range(100):
+        for task in tasks:
+            print(f'切换到任务{task.__name__} => ', end='')
+            try:
+                print(task.__next__())
+            except StopIteration as error:
+                print(error)
+
+
+if __name__ == '__main__':
+    main()

+ 53 - 0
Day16-20/code/example13.py

@@ -0,0 +1,53 @@
+"""
+魔术方法 - 哈希存储 / 上下文语法
+"""
+from random import randint
+
+
+class Student():
+    """学生"""
+
+    def __init__(self, stuid, name, gender):
+        self.stuid = stuid
+        self.name = name
+        self.gender = gender
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, exception_type, exception_value, traceback):
+        pass
+
+    def __hash__(self):
+        return hash(self.stuid)
+
+    def __eq__(self, other):
+        return self.stuid == other.stuid
+
+    def __repr__(self):
+        return f'{self.stuid}: {self.name}'
+
+
+def create_student():
+    return Student(randint(1001, 9999), 
+                   "无名氏", 
+                   "男" if randint(0, 1) == 1 else "女")
+
+
+def main():
+    """主函数"""
+    students = {
+        Student(1001, "王大锤", "男"),
+        Student(1001, "王小锤", "男"),
+        Student(1003, "王捶捶", "女")
+    }
+    print(len(students))
+    print(students)
+    with create_student() as stu:
+        print(stu.stuid)
+        print(stu.name)
+        print(stu.gender)
+
+
+if __name__ == '__main__':
+    main()

+ 0 - 65
Day31-35/玩转Linux操作系统.md

@@ -82,14 +82,12 @@ Linux内核是芬兰人Linus Torvalds开发的,于1991年9月发布。而Linux
 Linux系统的命令通常都是如下所示的格式:
 
 ```Shell
-
 命令名称 [命名参数] [命令对象]
 ```
 
 1. 获取登录信息 - **w** / **who** / **last**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# w
     23:31:16 up 12:16,  2 users,  load average: 0.00, 0.01, 0.05
    USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
@@ -107,7 +105,6 @@ Linux系统的命令通常都是如下所示的格式:
    Shell也被称为“壳”,它是用户与内核交流的翻译官,简单的说就是人与计算机交互的接口。目前很多Linux系统默认的Shell都是bash(<u>B</u>ourne <u>A</u>gain <u>SH</u>ell),因为它可以使用Tab键进行命令补全、可以保存历史命令、可以方便的配置环境变量以及执行批处理操作等。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# ps
      PID TTY          TIME CMD
     3531 pts/0    00:00:00 bash
@@ -117,7 +114,6 @@ Linux系统的命令通常都是如下所示的格式:
 3. 查看命令的说明 - **whatis**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# whatis ps
    ps (1)        - report a snapshot of the current processes.
    [root@izwz97tbgo9lkabnat2lo8z ~]# whatis python
@@ -127,7 +123,6 @@ Linux系统的命令通常都是如下所示的格式:
 4. 查看命令的位置 - **which** / **whereis**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# whereis ps
    ps: /usr/bin/ps /usr/share/man/man1/ps.1.gz
    [root@izwz97tbgo9lkabnat2lo8z ~]# whereis python
@@ -140,7 +135,6 @@ Linux系统的命令通常都是如下所示的格式:
 
 5. 查看帮助文档 - **man** / **info** / **apropos**。
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# ps --help
    Usage:
     ps [options]
@@ -163,7 +157,6 @@ Linux系统的命令通常都是如下所示的格式:
 6. 切换用户 - **su**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# su hellokitty
    [hellokitty@izwz97tbgo9lkabnat2lo8z root]$
    ```
@@ -171,7 +164,6 @@ Linux系统的命令通常都是如下所示的格式:
 7. 以管理员身份执行命令 - **sudo**。
 
    ```Shell
-   
    [jackfrued@izwz97tbgo9lkabnat2lo8z ~]$ ls /root
    ls: cannot open directory /root: Permission denied
    [jackfrued@izwz97tbgo9lkabnat2lo8z ~]$ sudo ls /root
@@ -184,7 +176,6 @@ Linux系统的命令通常都是如下所示的格式:
 8. 登入登出相关 - **logout** / **exit** / **adduser** / **userdel** / **passwd** / **ssh**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# adduser hellokitty
    [root@izwz97tbgo9lkabnat2lo8z ~]# passwd hellokitty
    Changing password for user jackfrued.
@@ -202,7 +193,6 @@ Linux系统的命令通常都是如下所示的格式:
 9. 查看系统和主机名 - **uname** / **hostname**。
 
    ```Shell
-   
    [root@izwz97tbgo9lkabnat2lo8z ~]# uname
    Linux
    [root@izwz97tbgo9lkabnat2lo8z ~]# hostname
@@ -216,7 +206,6 @@ Linux系统的命令通常都是如下所示的格式:
 11. 查看历史命令 - **history**。
 
     ```Shell
-    
     [root@iZwz97tbgo9lkabnat2lo8Z ~]# history
     ...
     452  ls
@@ -235,7 +224,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. 创建/删除目录 - **mkdir** / **rmdir**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir abc
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir -p xyz/abc
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# rmdir abc
@@ -244,7 +232,6 @@ Linux系统的命令通常都是如下所示的格式:
 2. 创建/删除文件 - **touch** / **rm**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# touch readme.txt
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# touch error.txt
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# rm error.txt
@@ -276,7 +263,6 @@ Linux系统的命令通常都是如下所示的格式:
 5. 查看文件内容 - **cat** / **head** / **tail** / **more** / **less**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://www.sohu.com/ -O sohu.html
    --2018-06-20 18:42:34--  http://www.sohu.com/
    Resolving www.sohu.com (www.sohu.com)... 14.18.240.6
@@ -310,7 +296,6 @@ Linux系统的命令通常都是如下所示的格式:
 6. 拷贝/移动文件 - **cp** / **mv**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# mkdir backup
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cp sohu.html backup/
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cd backup
@@ -324,7 +309,6 @@ Linux系统的命令通常都是如下所示的格式:
 7. 查找文件和查找内容 - **find** / **grep**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# find / -name "*.html"
    /root/sohu.html
    /root/backup/sohu_index.html
@@ -348,7 +332,6 @@ Linux系统的命令通常都是如下所示的格式:
 8. 链接 - **ln**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l sohu.html
    -rw-r--r-- 1 root root 212131 Jun 20 19:15 sohu.html
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ln /root/sohu.html /root/backup/sohu_backup
@@ -371,7 +354,6 @@ Linux系统的命令通常都是如下所示的格式:
 9. 压缩/解压缩和归档/解归档 - **gzip** / **gunzip** / **xz** / **tar**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://download.redis.io/releases/redis-4.0.10.tar.gz
    --2018-06-20 19:29:59--  http://download.redis.io/releases/redis-4.0.10.tar.gz
    Resolving download.redis.io (download.redis.io)... 109.74.203.151
@@ -412,7 +394,6 @@ Linux系统的命令通常都是如下所示的格式:
 10. 其他工具 - **sort** / **uniq** / **diff** / **tr** / **cut** / **paste** / **file** / **wc**。
 
   ```Shell
-  
   [root@iZwz97tbgo9lkabnat2lo8Z ~]# cat foo.txt
   grape
   apple
@@ -461,7 +442,6 @@ Linux系统的命令通常都是如下所示的格式:
    例子:查找当前目录下文件个数。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# find ./ | wc -l
    6152
    ```
@@ -469,7 +449,6 @@ Linux系统的命令通常都是如下所示的格式:
    例子:列出当前路径下的文件和文件夹,给每一项加一个编号。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ls | cat -n
         1  dump.rdb
         2  mongodb-3.6.5
@@ -481,14 +460,12 @@ Linux系统的命令通常都是如下所示的格式:
    例子:查找record.log中包含AAA,但不包含BBB的记录的总数
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cat record.log | grep AAA | grep -v BBB | wc -l
    ```
 
 2. 输出重定向和错误重定向 - **\>** / **>>** / **2\>**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cat readme.txt
    banana
    apple
@@ -511,7 +488,6 @@ Linux系统的命令通常都是如下所示的格式:
 3. 输入重定向 - **\<**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# echo 'hello, world!' > hello.txt
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# wall < hello.txt
    [root@iZwz97tbgo9lkabnat2lo8Z ~]#
@@ -530,7 +506,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. **alias**
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# alias ll='ls -l'
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# alias frm='rm -rf'
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ll
@@ -543,7 +518,6 @@ Linux系统的命令通常都是如下所示的格式:
 2. **unalias**
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# unalias frm
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# frm sohu.html
    -bash: frm: command not found
@@ -554,7 +528,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. 时间和日期 - **date** / **cal**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# date
    Wed Jun 20 12:53:19 CST 2018
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cal
@@ -615,7 +588,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. **chmod** - 改变文件模式比特。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
    ...
    -rw-r--r--  1 root       root 211878 Jun 19 16:06 sohu.html
@@ -640,7 +612,6 @@ Linux系统的命令通常都是如下所示的格式:
 2. **chown** - 改变文件所有者。
 
     ```Shell
-       
     [root@iZwz97tbgo9lkabnat2lo8Z ~]# ls -l
     ...
     -rw-r--r--  1 root root     54 Jun 20 10:06 readme.txt
@@ -657,7 +628,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. 列出文件系统的磁盘使用状况 - **df**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# df -h
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/vda1        40G  5.0G   33G  14% /
@@ -671,7 +641,6 @@ Linux系统的命令通常都是如下所示的格式:
 2. 磁盘分区表操作 - **fdisk**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# fdisk -l
    Disk /dev/vda: 42.9 GB, 42949672960 bytes, 83886080 sectors
    Units = sectors of 1 * 512 = 512 bytes
@@ -698,7 +667,6 @@ Linux系统的命令通常都是如下所示的格式:
 1. 启动vim。可以通过`vi`或`vim`命令来启动vim,启动时可以指定文件名来打开一个文件,如果没有指定文件名,也可以在保存的时候指定文件名。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# vim guess.py
    ```
 
@@ -747,7 +715,6 @@ Linux系统的命令通常都是如下所示的格式:
    - 比较多个文件。
 
      ```Shell
-     
      [root@iZwz97tbgo9lkabnat2lo8Z ~]# vim -d foo.txt bar.txt
      ```
      ![](./res/vim-diff.png)
@@ -755,7 +722,6 @@ Linux系统的命令通常都是如下所示的格式:
    - 打开多个文件。
 
      ```Shell
-     
      [root@iZwz97tbgo9lkabnat2lo8Z ~]# vim foo.txt bar.txt hello.txt
      ```
 
@@ -812,7 +778,6 @@ Linux系统的命令通常都是如下所示的格式:
 下面以Nginx为例,演示如何使用yum安装软件。
 
 ```Shell
-
 [root@iZwz97tbgo9lkabnat2lo8Z ~]# yum -y install nginx
 ...
 Installed:
@@ -851,7 +816,6 @@ nginx version: nginx/1.12.2
 移除Nginx。
 
 ```Shell
-
 [root@iZwz97tbgo9lkabnat2lo8Z ~]# nginx -s stop
 [root@iZwz97tbgo9lkabnat2lo8Z ~]# yum -y remove nginx
 ```
@@ -859,7 +823,6 @@ nginx version: nginx/1.12.2
 下面以MySQL为例,演示如何使用rpm安装软件。要安装MySQL需要先到[MySQL官方网站](https://www.mysql.com/)下载对应的[RPM文件](https://dev.mysql.com/downloads/mysql/),当然要选择和你使用的Linux系统对应的版本。MySQL现在是Oracle公司旗下的产品,在MySQL被收购后,MySQL的作者重新制作了一个MySQL的分支MariaDB,可以通过yum进行安装。如果要安装MySQL需要先通过yum删除`mariadb-libs`这个可能会跟MySQL底层库冲突的库,然后还需要安装一个名为`libaio`的依赖库。
 
 ```Shell
-
 [root@iZwz97tbgo9lkabnat2lo8Z mysql]# ls
 mysql-community-client-5.7.22-1.el7.x86_64.rpm
 mysql-community-common-5.7.22-1.el7.x86_64.rpm
@@ -878,7 +841,6 @@ Preparing...                          ################################# [100%]
 移除安装的MySQL。
 
 ```Shell
-
 [root@iZwz97tbgo9lkabnat2lo8Z ~]# rpm -qa | grep mysql | xargs rpm -e
 ```
 
@@ -887,7 +849,6 @@ Preparing...                          ################################# [100%]
 下面以安装MongoDB为例,演示这类软件应该如何安装。
 
 ```Shell
-
 [root@iZwz97tbgo9lkabnat2lo8Z ~]# wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz
 --2018-06-21 18:32:53--  https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.6.5.tgz
 Resolving fastdl.mongodb.org (fastdl.mongodb.org)... 52.85.83.16, 52.85.83.228, 52.85.83.186, ...
@@ -952,7 +913,6 @@ build environment:
 1. 安装Python 3.6。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# yum install gcc
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# wget https://www.python.org/ftp/python/3.6.5/Python-3.6.5.tgz
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# gunzip Python-3.6.5.tgz
@@ -972,7 +932,6 @@ build environment:
 2. 安装Redis-3.2.12。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# wget http://download.redis.io/releases/redis-3.2.12.tar.gz
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# gunzip redis-3.2.12.tar.gz
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# tar -xvf redis-3.2.12.tar
@@ -989,35 +948,30 @@ build environment:
 1. 启动服务。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl start firewalld
    ```
 
 2. 终止服务。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl stop firewalld
    ```
 
 3. 重启服务。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl restart firewalld
    ```
 
 4. 查看服务。
 
     ```Shell
-    
     [root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl status firewalld
     ```
 
 5. 设置是否开机自启。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# systemctl enable firewalld
    Created symlink from /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service to /usr/lib/systemd/system/firewalld.service.
    Created symlink from /etc/systemd/system/multi-user.target.wants/firewalld.service to /usr/lib/systemd/system/firewalld.service.
@@ -1031,7 +985,6 @@ build environment:
 1. **crontab**命令。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# crontab -e
    * * * * * echo "hello, world!" >> /root/hello.txt
    59 23 * * * rm -f /root/*.log
@@ -1041,7 +994,6 @@ build environment:
 2. crontab相关文件。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# cd /etc
    [root@iZwz97tbgo9lkabnat2lo8Z etc]# ls -l | grep cron
    -rw-------.  1 root root      541 Aug  3  2017 anacrontab
@@ -1081,7 +1033,6 @@ build environment:
 2. 显示/操作网络配置(旧) - **ifconfig**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ifconfig eth0
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 172.18.61.250  netmask 255.255.240.0  broadcast 172.18.63.255
@@ -1095,7 +1046,6 @@ build environment:
 3. 显示/操作网络配置(新) - **ip**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ip address
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
@@ -1110,7 +1060,6 @@ build environment:
 4. 网络可达性检查 - **ping**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ping www.baidu.com -c 3
    PING www.a.shifen.com (220.181.111.188) 56(84) bytes of data.
    64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=1 ttl=51 time=36.3 ms
@@ -1124,21 +1073,18 @@ build environment:
 5. 查看网络服务和端口 - **netstat**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# netstat -nap | grep nginx
    ```
 
 6. 安全文件拷贝 - **scp**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# scp root@1.2.3.4:/root/guido.jpg hellokitty@4.3.2.1:/home/hellokitty/pic.jpg
    ```
 
 7. 安全文件传输 - **sftp**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# sftp root@120.77.222.217
    root@120.77.222.217's password:
    Connected to 120.77.222.217.
@@ -1168,7 +1114,6 @@ build environment:
 1. **ps** - 查询进程。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ps -ef
    UID        PID  PPID  C STIME TTY          TIME CMD
    root         1     0  0 Jun23 ?        00:00:05 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
@@ -1182,7 +1127,6 @@ build environment:
 2. **kill** - 终止进程。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# kill 1234
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# kill -9 1234
    ```
@@ -1190,7 +1134,6 @@ build environment:
    例子:用一条命令强制终止正在运行的Redis进程。
 
     ```Shell
-   
    ps -ef | grep redis | grep -v grep | awk '{print $2}' | xargs kill
     ```
 
@@ -1200,7 +1143,6 @@ build environment:
    - `&`
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# mongod &
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# redis-server
    ...
@@ -1211,7 +1153,6 @@ build environment:
 4. **jobs** - 查询后台进程。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# jobs
    [2]   Running                 mongod &
    [3]-  Stopped                 cat
@@ -1221,7 +1162,6 @@ build environment:
 5. **bg** - 让进程在后台继续运行。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# bg %4
    [4]+ redis-server &
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# jobs
@@ -1233,7 +1173,6 @@ build environment:
 6. **fg** - 将后台进程置于前台。
 
     ```Shell
-    
     [root@iZwz97tbgo9lkabnat2lo8Z ~]# fg %4
     redis-server
     ^C5554:signal-handler (1530025281) Received SIGINT scheduling shutdown...
@@ -1248,7 +1187,6 @@ build environment:
 7. **top** - 进程监控。
 
     ```Shell
-    
     [root@iZwz97tbgo9lkabnat2lo8Z ~]# top
     top - 23:04:23 up 3 days, 14:10,  1 user,  load average: 0.00, 0.01, 0.05
     Tasks:  65 total,   1 running,  64 sleeping,   0 stopped,   0 zombie
@@ -1265,7 +1203,6 @@ build environment:
 2. 查看内存使用情况 - **free**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# free
                  total        used        free      shared  buff/cache   available
    Mem:        1016168      323924      190452         356      501792      531800
@@ -1275,7 +1212,6 @@ build environment:
 3. 查看进程使用内存状况 - **pmap**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# ps
      PID TTY          TIME CMD
     4581 pts/0    00:00:00 bash
@@ -1295,7 +1231,6 @@ build environment:
 4. 报告设备CPU和I/O统计信息 - **iostat**。
 
    ```Shell
-   
    [root@iZwz97tbgo9lkabnat2lo8Z ~]# iostat
    Linux 3.10.0-693.11.1.el7.x86_64 (iZwz97tbgo9lkabnat2lo8Z)      06/26/2018      _x86_64_       (1 CPU)
    avg-cpu:  %user   %nice %system %iowait  %steal   %idle

+ 88 - 0
Day36-40/code/HRS_create_and_init.sql

@@ -0,0 +1,88 @@
+-- 创建人力资源管理系统数据库
+drop database if exists HRS;
+create database HRS default charset utf8;
+-- 切换数据库上下文环境
+use HRS;
+-- 删除表
+drop table if exists TbEmp;
+drop table if exists TbDept;
+-- 创建部门表
+create table TbDept
+(
+deptno tinyint primary key,	-- 部门编号
+dname varchar(10) not null,	-- 部门名称
+dloc varchar(20) not null	-- 部门所在地
+);
+-- 添加部门记录
+insert into TbDept values (10, '会计部', '北京');
+insert into TbDept values (20, '研发部', '成都');
+insert into TbDept values (30, '销售部', '重庆');
+insert into TbDept values (40, '运维部', '深圳');
+-- 创建员工表
+create table TbEmp
+(
+empno int primary key,		-- 员工编号
+ename varchar(20) not null,	-- 员工姓名
+job varchar(20) not null,	-- 员工职位
+mgr int,					-- 主管编号
+sal int not null,			-- 员工月薪
+comm int,					-- 每月补贴
+dno tinyint					-- 所在部门编号
+);
+-- 添加外键约束
+alter table TbEmp add constraint fk_dno foreign key (dno) references TbDept(deptno);
+-- 添加员工记录
+insert into TbEmp values (7800, '张三丰', '总裁', null, 9000, 1200, 20);
+insert into TbEmp values (2056, '乔峰', '分析师', 7800, 5000, 1500, 20);
+insert into TbEmp values (3088, '李莫愁', '设计师', 2056, 3500, 800, 20);
+insert into TbEmp values (3211, '张无忌', '程序员', 2056, 3200, null, 20);
+insert into TbEmp values (3233, '丘处机', '程序员', 2056, 3400, null, 20);
+insert into TbEmp values (3251, '张翠山', '程序员', 2056, 4000, null, 20);
+insert into TbEmp values (5566, '宋远桥', '会计师', 7800, 4000, 1000, 10);
+insert into TbEmp values (5234, '郭靖', '出纳', 5566, 2000, null, 10);
+insert into TbEmp values (3344, '黄蓉', '销售主管', 7800, 3000, 800, 30);
+insert into TbEmp values (1359, '胡一刀', '销售员', 3344, 1800, 200, 30);
+insert into TbEmp values (4466, '苗人凤', '销售员', 3344, 2500, null, 30);
+insert into TbEmp values (3244, '欧阳锋', '程序员', 3088, 3200, null, 20);
+insert into TbEmp values (3577, '杨过', '会计', 5566, 2200, null, 10);
+insert into TbEmp values (3588, '朱九真', '会计', 5566, 2500, null, 10);
+
+-- 查询薪资最高的员工姓名和工资
+
+-- 查询员工的姓名和年薪((月薪+补贴)*12)
+
+-- 查询有员工的部门的编号和人数
+
+-- 查询所有部门的名称和人数
+
+-- 查询薪资最高的员工(Boss除外)的姓名和工资
+
+-- 查询薪水超过平均薪水的员工的姓名和工资
+
+-- 查询薪水超过其所在部门平均薪水的员工的姓名、部门编号和工资
+
+-- 查询部门中薪水最高的人姓名、工资和所在部门名称
+
+-- 查询主管的姓名和职位
+
+-- 查询薪资排名4~6名的员工姓名和工资
+
+use HRS;
+
+drop procedure if exists sp_avg_sal_by_dept;
+
+
+create procedure sp_avg_sal_by_dept(deptno integer, out avg_sal float)
+begin 
+    select avg(sal) into avg_sal from TbEmp where dno=deptno;
+end;
+
+
+
+
+call sp_avg_sal_by_dept(10, @avgSal);
+
+select @avgSal;
+
+
+

+ 251 - 0
Day36-40/code/SRS_create_and_init.sql

@@ -0,0 +1,251 @@
+-- 创建SRS数据库
+drop database if exists SRS;
+create database SRS default charset utf8 collate utf8_bin;
+
+-- 切换到SRS数据库
+use SRS;
+
+-- 创建学院表
+create table tb_college
+(
+collid int not null auto_increment comment '学院编号',
+collname varchar(50) not null comment '学院名称',
+collmaster varchar(20) not null comment '院长姓名',
+collweb varchar(511) default '' comment '学院网站',
+primary key (collid)
+);
+
+-- 添加唯一约束
+alter table tb_college add constraint uni_college_collname unique (collname);
+
+-- 创建学生表
+create table tb_student
+(
+stuid int not null comment '学号',
+sname varchar(20) not null comment '学生姓名',
+gender bit default 1 comment '性别',
+birth date not null comment '出生日期',
+addr varchar(255) default '' comment '籍贯',
+collid int not null comment '所属学院编号',
+primary key (stuid)
+);
+
+-- 添加外键约束
+alter table tb_student add constraint fk_student_collid foreign key (collid) references tb_college (collid);
+
+-- 创建教师表
+create table tb_teacher
+(
+teaid int not null comment '教师工号',
+tname varchar(20) not null comment '教师姓名',
+title varchar(10) default '' comment '职称',
+collid int not null comment '所属学院编号'
+);
+
+-- 添加主键约束
+alter table tb_teacher add constraint pk_teacher primary key (teaid);
+
+-- 添加外键约束
+alter table tb_teacher add constraint fk_teacher_collid foreign key (collid) references tb_college (collid);
+
+-- 创建课程表
+create table tb_course
+(
+couid int not null comment '课程编号',
+cname varchar(50) not null comment '课程名称',
+credit tinyint not null comment '学分',
+teaid int not null comment '教师工号',
+primary key (couid)
+);
+
+-- 添加外键约束
+alter table tb_course add constraint fk_course_tid foreign key (teaid) references tb_teacher (teaid);
+
+-- 创建学生选课表
+create table tb_score
+(
+scid int not null auto_increment comment '选课编号',
+sid int not null comment '学号',
+cid int not null comment '课程编号',
+seldate date comment '选课时间日期',
+mark decimal(4,1) comment '考试成绩',
+primary key (scid)
+);
+
+-- 添加外键约束
+alter table tb_score add constraint fk_score_sid foreign key (sid) references tb_student (stuid);
+alter table tb_score add constraint fk_score_cid foreign key (cid) references tb_course (couid);
+-- 添加唯一约束
+alter table tb_score add constraint uni_score_sid_cid unique (sid, cid);
+
+
+-- 插入学院数据
+insert into tb_college (collname, collmaster, collweb) values 
+('计算机学院', '左冷禅', 'http://www.abc.com'),
+('外国语学院', '岳不群', 'http://www.xyz.com'),
+('经济管理学院', '风清扬', 'http://www.foo.com');
+
+-- 插入学生数据
+insert into tb_student (stuid, sname, gender, birth, addr, collid) values
+(1001, '杨逍', 1, '1990-3-4', '四川成都', 1),
+(1002, '任我行', 1, '1992-2-2', '湖南长沙', 1),
+(1033, '王语嫣', 0, '1989-12-3', '四川成都', 1),
+(1572, '岳不群', 1, '1993-7-19', '陕西咸阳', 1),
+(1378, '纪嫣然', 0, '1995-8-12', '四川绵阳', 1),
+(1954, '林平之', 1, '1994-9-20', '福建莆田', 1),
+(2035, '东方不败', 1, '1988-6-30', null, 2),
+(3011, '林震南', 1, '1985-12-12', '福建莆田', 3),
+(3755, '项少龙', 1, '1993-1-25', null, 3),
+(3923, '杨不悔', 0, '1985-4-17', '四川成都', 3);
+
+-- 插入老师数据
+insert into tb_teacher (teaid, tname, title, collid) values 
+(1122, '张三丰', '教授', 1),
+(1133, '宋远桥', '副教授', 1),
+(1144, '杨逍', '副教授', 1),
+(2255, '范遥', '副教授', 2),
+(3366, '韦一笑', '讲师', 3);
+
+-- 插入课程数据
+insert into tb_course (couid, cname, credit, teaid) values 
+(1111, 'Python程序设计', 3, 1122),
+(2222, 'Web前端开发', 2, 1122),
+(3333, '操作系统', 4, 1122),
+(4444, '计算机网络', 2, 1133),
+(5555, '编译原理', 4, 1144),
+(6666, '算法和数据结构', 3, 1144),
+(7777, '经贸法语', 3, 2255),
+(8888, '成本会计', 2, 3366),
+(9999, '审计学', 3, 3366);
+
+-- 插入选课数据
+insert into tb_score (sid, cid, seldate, mark) values 
+(1001, 1111, '2017-09-01', 95),
+(1001, 2222, '2017-09-01', 87.5),
+(1001, 3333, '2017-09-01', 100),
+(1001, 4444, '2018-09-03', null),
+(1001, 6666, '2017-09-02', 100),
+(1002, 1111, '2017-09-03', 65),
+(1002, 5555, '2017-09-01', 42),
+(1033, 1111, '2017-09-03', 92.5),
+(1033, 4444, '2017-09-01', 78),
+(1033, 5555, '2017-09-01', 82.5),
+(1572, 1111, '2017-09-02', 78),
+(1378, 1111, '2017-09-05', 82),
+(1378, 7777, '2017-09-02', 65.5),
+(2035, 7777, '2018-09-03', 88),
+(2035, 9999, date(now()), null),
+(3755, 1111, date(now()), null),
+(3755, 8888, date(now()), null),
+(3755, 9999, '2017-09-01', 92);
+
+-- 查询所有学生信息
+select * from tb_student;
+-- 查询所有课程名称及学分(投影和别名)
+select cname as 课程名称, credit as 学分 from tb_course;
+-- 查询所有女学生的姓名和出生日期(筛选)
+select sname as 姓名, birth as 出生日期 from tb_student where gender=0;
+-- 查询所有80后学生的姓名、性别和出生日期(筛选)
+select sname, gender, birth from tb_student where birth between '1980-1-1' and '1989-12-31';
+-- 查询姓”杨“的学生姓名和性别(模糊)
+select sname, gender from tb_student where sname like '杨%';
+-- 查询姓”杨“名字两个字的学生姓名和性别(模糊)
+select sname, gender from tb_student where sname like '杨_';
+-- 查询姓”杨“名字三个字的学生姓名和性别(模糊)
+select sname, gender from tb_student where sname like '杨__';
+-- 查询名字中有”不“字或“嫣”字的学生的姓名(模糊)
+select sname from tb_student where sname like '%不%' or sname like '%嫣%';
+-- 查询没有录入家庭住址的学生姓名(空值)
+select sname from tb_student where addr is null or addr='';
+-- 查询录入了家庭住址的学生姓名(空值)
+select sname from tb_student where addr is not null and addr<>'';
+-- 查询学生选课的所有日期(去重)
+select distinct seldate from tb_score;
+-- 查询学生的家庭住址(去重)
+select distinct addr from tb_student where addr is not null and addr<>'';
+-- 查询男学生的姓名和生日按年龄从大到小排列(排序)
+select sname, birth from tb_student where gender=1 order by birth asc;
+-- max() / min() / sum() / avg() / count()
+-- 查询年龄最大的学生的出生日期(聚合函数)
+select min(birth) from tb_student;
+-- 查询年龄最小的学生的出生日期(聚合函数)
+select max(birth) from tb_student;
+-- 查询男女学生的人数(分组和聚合函数)
+select if(gender, '男', '女') as 性别, count(gender) as 人数 
+from tb_student group by gender;
+-- 查询课程编号为1111的课程的平均成绩(筛选和聚合函数)
+select avg(mark) as 平均分 from tb_score where cid=1111;
+-- 查询学号为1001的学生所有课程的平均分(筛选和聚合函数)
+select avg(mark) as 平均分 from tb_score where sid=1001;
+-- 查询每个学生的学号和平均成绩(分组和聚合函数)
+select sid, avg(mark) from tb_score where mark is not null group by sid;
+-- 查询平均成绩大于等于90分的学生的学号和平均成绩
+select sid, avg(mark) from tb_score group by sid having avg(mark)>=90;
+-- 子查询 - 在一个查询中又使用到了另外一个查询的结果
+-- 查询年龄最大的学生的姓名(子查询)
+select sname from tb_student where birth=(select min(birth) from tb_student);
+-- 查询年龄最大的学生姓名和年龄(子查询+运算)
+select sname as 姓名, year(now()) - year(birth) as 年龄 
+from tb_student where birth=(select min(birth) from tb_student);
+-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
+select sname from tb_student where stuid in ( 
+select sid from tb_score group by sid having count(sid)>2);
+-- 连接查询(联结查询/联接查询)
+-- 查询学生姓名、课程名称以及成绩
+select sname, cname, mark 
+from tb_score t1, tb_student t2, tb_course t3 
+where t2.stuid=t1.sid and t3.couid=t1.cid and mark is not null;
+
+select sname, cname, mark from tb_student t1 
+inner join tb_score t2 on t1.stuid=t2.sid 
+inner join tb_course t3 on t3.couid=t2.cid 
+where mark is not null;
+-- 查询选课学生的姓名和平均成绩(子查询和连接查询)
+select sname, avgmark from tb_student t1, 
+(select sid, avg(mark) as avgmark from tb_score group by sid) t2 
+where stuid=sid;
+
+select sname, avgmark from tb_student inner join 
+(select sid, avg(mark) as avgmark from tb_score group by sid) t2 
+on stuid=sid;
+-- 注意:在连接查询时如果没有给出连接条件就会形成笛卡尔积
+
+-- 查询每个学生的姓名和选课数量(左外连接和子查询)
+-- 左外连接 - 把左表(写在前面的表)不满足连接条件的记录也查出来对应记录补null值
+-- 右外连接 - 把右表(写在后面的表)不满足连接条件的记录也查出来对应记录补null值
+select sname, total from tb_student left join 
+(select sid, count(sid) as total from tb_score group by sid) tb_temp 
+on stuid=sid;
+
+-- DDL (Data Definition Language)
+-- DML (Data Manipulation Language)
+-- DCL (Data Control Language)
+
+-- 创建名为hellokitty的用户并设置口令
+create user 'hellokitty'@'%' identified by '123123';
+
+-- 授权
+grant select on srs.* to 'hellokitty'@'%';
+grant insert, delete, update on srs.* to 'hellokitty'@'%';
+grant create, drop, alter on srs.* to 'hellokitty'@'%';
+
+grant all privileges on srs.* to 'hellokitty'@'%';
+grant all privileges on srs.* to 'hellokitty'@'%' with grant option;
+
+-- 召回
+revoke all privileges on srs.* from 'hellokitty'@'%';
+
+-- 事务控制
+-- 开启事务环境
+begin;
+-- start transaction;
+update tb_score set mark=mark-2 where sid=1001 and mark is not null;
+update tb_score set mark=mark+2 where sid=1002 and mark is not null;
+-- 事务提交
+commit;
+ -- 事务回滚
+rollback;
+
+begin;
+delete from tb_score;
+rollback;

+ 15 - 0
Day36-40/code/all/Bank_create_and_init.sql

@@ -0,0 +1,15 @@
+drop database if exists Bank;
+
+create database Bank default charset utf8;
+
+use Bank;
+
+create table TbAccount
+(
+accid char(8) primary key,
+accowner varchar(20) not null,
+accbalance float not null default 0
+);
+
+insert into TbAccount values (11223344, '王大锤', 1000);
+insert into TbAccount values (22334455, '李小龙', 1000);

+ 27 - 0
Day36-40/code/all/Demo_create_and_init.sql

@@ -0,0 +1,27 @@
+drop database if exists demo;
+create database demo default charset utf8 collate utf8_general_ci;
+
+use demo;
+
+create table tb_teacher
+(
+teacherid int not null auto_increment,
+tname varchar(20) not null,
+tjob varchar(20) not null,
+tintro varchar(1023) default '',
+tmotto varchar(255) default '',
+primary key (teacherid)
+);
+
+insert into tb_teacher (tname, tjob, tintro, tmotto) values 
+('骆昊', 'Python教学主管', '10年以上软硬件产品和系统设计、研发、架构和管理经验,2003年毕业于四川大学,四川大学Java技术俱乐部创始人,四川省优秀大学毕业生,在四川省网络通信技术重点实验室工作期间,参与了2项国家自然科学基金项目、1项中国科学院中长期研究项目和多项四川省科技攻关项目,在国际会议和国内顶级期刊上发表多篇论文(1篇被SCI收录,3篇被EI收录),大规模网络性能测量系统DMC-TS的设计者和开发者,perf-TTCN语言的发明者。国内最大程序员社区CSDN的博客专家,在Github上参与和维护了多个高质量开源项目,精通C/C++、Java、Python、R、Swift、JavaScript等编程语言,擅长OOAD、系统架构、算法设计、协议分析和网络测量,主持和参与过电子政务系统、KPI考核系统、P2P借贷平台等产品的研发,一直践行“用知识创造快乐”的教学理念,善于总结,乐于分享。', '教育是让受教育者体会用知识创造快乐的过程'),
+('肖世荣', 'Python高级讲师', '10年以上互联网和移动互联网产品设计、研发、技术架构和项目管理经验,曾在中国移动、symbio、ajinga.com、万达信息等公司担任架构师、项目经理、技术总监等职务,长期为苹果、保时捷、耐克、沃尔玛等国际客户以及国内的政府机构提供信息化服务,主导的项目曾获得“世界科技先锋”称号,个人作品“许愿吧”曾在腾讯应用市场生活类App排名前3,拥有百万级用户群体,运营的公众号“卵石坊”是国内知名的智能穿戴设备平台。精通Python、C++、Java、Ruby、JavaScript等开发语言,主导和参与了20多个企业级项目(含国家级重大项目和互联网创新项目),涉及的领域包括政务、社交、电信、卫生和金融,有极为丰富的项目实战经验。授课深入浅出、条理清晰,善于调动学员的学习热情并帮助学员理清思路和方法。', '世上没有绝望的处境,只有对处境绝望的人'),
+('余婷', 'Python高级讲师', '5年以上移动互联网项目开发经验和教学经验,曾担任上市游戏公司高级软件研发工程师和移动端(iOS)技术负责人,参了多个企业级应用和游戏类应用的移动端开发和后台服务器开发,拥有丰富的开发经验和项目管理经验,以个人开发者和协作开发者的身份在苹果的AppStore上发布过多款App。精通Python、C、Objective-C、Swift等开发语言,熟悉iOS原生App开发、RESTful接口设计以及基于Cocos2d-x的游戏开发。授课条理清晰、细致入微,性格活泼开朗、有较强的亲和力,教学过程注重理论和实践的结合,在学员中有良好的口碑。', '每天叫醒你的不是闹钟而是梦想'),
+('王海飞', 'Python高级讲师', '5年以上Python开发经验,先后参与了O2O商城、CRM系统、CMS平台、ERP系统等项目的设计与研发,曾在全国最大最专业的汽车领域相关服务网站担任Python高级研发工程师、项目经理等职务,擅长基于Python、Java、PHP等开发语言的企业级应用开发,全程参与了多个企业级应用从需求到上线所涉及的各种工作,精通Django、Flask等框架,熟悉基于微服务的企业级项目开发,拥有丰富的项目实战经验。善于用浅显易懂的方式在课堂上传授知识点,在授课过程中经常穿插企业开发的实际案例并分析其中的重点和难点,通过这种互动性极强的教学模式帮助学员找到解决问题的办法并提升学员的综合素质。', '不要给我说什么底层原理、框架内核!老夫敲代码就是一把梭!复制!黏贴!拿起键盘就是干!'),
+('何翰宇', 'JavaEE高级讲师', '5年以上JavaEE项目开发和教学经验,参与过人力资源管理系统、电子教育产品在线商城、平安好医生App、平安好车主App等项目的设计与研发。擅长Java语言、面向对象编程、JavaEE框架、Web前端开发、数据库编程和Android应用开发,对新技术有着浓厚的兴趣和钻研精神,对微服务架构、虚拟化技术、区块链、边缘计算等领域都有自己独到的认识和见解,有丰富的项目经验和教学经验。授课时注重学习方法的引导,提倡以项目为导向的实战型教学,同时也注重基础知识的掌握和底层原理的理解,课堂氛围轻松幽默,能够把枯燥乏味的知识变成生动有趣的案例,帮助学员更快更好的掌握技术的要领,从事JavaEE教学工作以来,获得了学生潮水般的好评。', '每天撸代码,生活乐无边!'),
+('吴明富', 'HTML5教学主管', '毕业于西南交通大学,高级软件研发工程师,10年以上的开发和培训经验。曾就职于华为赛门铁克科技有限公司,负责公司内部ERP系统的研发,参与和主导过多个大型门户网站、电子商务网站、电子政务系统以及多个企业级Web项目的设计和开发,同时负责过多门企业内训课程的研发与讲授,有着非常丰富的JavaEE项目开发经验和Web前端开发经验,精通C/C++、Java、PHP、JavaScript等开发语言,能够使用多种技术进行全栈开发。授课经验丰富、思路清晰、富有激情,对知识点的讲解由浅入深、深入浅出,能够通过实际开发的场景引导学员思考业务并理解相关技术,善于将多年的项目实战经验和企业内训经验融入课堂,通过理论联系实际的方式帮助学员迅速提升就业能力。', '人生的道路在态度的岔口一分为二');
+
+
+
+
+

+ 88 - 0
Day36-40/code/all/HRS_create_and_init.sql

@@ -0,0 +1,88 @@
+-- 创建人力资源管理系统数据库
+drop database if exists HRS;
+create database HRS default charset utf8;
+-- 切换数据库上下文环境
+use HRS;
+-- 删除表
+drop table if exists TbEmp;
+drop table if exists TbDept;
+-- 创建部门表
+create table TbDept
+(
+deptno tinyint primary key,	-- 部门编号
+dname varchar(10) not null,	-- 部门名称
+dloc varchar(20) not null	-- 部门所在地
+);
+-- 添加部门记录
+insert into TbDept values (10, '会计部', '北京');
+insert into TbDept values (20, '研发部', '成都');
+insert into TbDept values (30, '销售部', '重庆');
+insert into TbDept values (40, '运维部', '深圳');
+-- 创建员工表
+create table TbEmp
+(
+empno int primary key,		-- 员工编号
+ename varchar(20) not null,	-- 员工姓名
+job varchar(20) not null,	-- 员工职位
+mgr int,					-- 主管编号
+sal int not null,			-- 员工月薪
+comm int,					-- 每月补贴
+dno tinyint					-- 所在部门编号
+);
+-- 添加外键约束
+alter table TbEmp add constraint fk_dno foreign key (dno) references TbDept(deptno);
+-- 添加员工记录
+insert into TbEmp values (7800, '张三丰', '总裁', null, 9000, 1200, 20);
+insert into TbEmp values (2056, '乔峰', '分析师', 7800, 5000, 1500, 20);
+insert into TbEmp values (3088, '李莫愁', '设计师', 2056, 3500, 800, 20);
+insert into TbEmp values (3211, '张无忌', '程序员', 2056, 3200, null, 20);
+insert into TbEmp values (3233, '丘处机', '程序员', 2056, 3400, null, 20);
+insert into TbEmp values (3251, '张翠山', '程序员', 2056, 4000, null, 20);
+insert into TbEmp values (5566, '宋远桥', '会计师', 7800, 4000, 1000, 10);
+insert into TbEmp values (5234, '郭靖', '出纳', 5566, 2000, null, 10);
+insert into TbEmp values (3344, '黄蓉', '销售主管', 7800, 3000, 800, 30);
+insert into TbEmp values (1359, '胡一刀', '销售员', 3344, 1800, 200, 30);
+insert into TbEmp values (4466, '苗人凤', '销售员', 3344, 2500, null, 30);
+insert into TbEmp values (3244, '欧阳锋', '程序员', 3088, 3200, null, 20);
+insert into TbEmp values (3577, '杨过', '会计', 5566, 2200, null, 10);
+insert into TbEmp values (3588, '朱九真', '会计', 5566, 2500, null, 10);
+
+-- 查询薪资最高的员工姓名和工资
+
+-- 查询员工的姓名和年薪((月薪+补贴)*12)
+
+-- 查询有员工的部门的编号和人数
+
+-- 查询所有部门的名称和人数
+
+-- 查询薪资最高的员工(Boss除外)的姓名和工资
+
+-- 查询薪水超过平均薪水的员工的姓名和工资
+
+-- 查询薪水超过其所在部门平均薪水的员工的姓名、部门编号和工资
+
+-- 查询部门中薪水最高的人姓名、工资和所在部门名称
+
+-- 查询主管的姓名和职位
+
+-- 查询薪资排名4~6名的员工姓名和工资
+
+use HRS;
+
+drop procedure if exists sp_avg_sal_by_dept;
+
+
+create procedure sp_avg_sal_by_dept(deptno integer, out avg_sal float)
+begin 
+    select avg(sal) into avg_sal from TbEmp where dno=deptno;
+end;
+
+
+
+
+call sp_avg_sal_by_dept(10, @avgSal);
+
+select @avgSal;
+
+
+

+ 31 - 0
Day36-40/code/all/Library_create_and_init.sql

@@ -0,0 +1,31 @@
+drop database if exists Library;
+
+create database Library default charset utf8;
+
+use Library;
+
+create table TbBook
+(
+bookid integer primary key auto_increment,
+title varchar(100) not null,
+author varchar(50) not null,
+publisher varchar(50) not null,
+price float not null,
+lendout bit default 0,
+lenddate datetime,
+lendcount integer default 0
+);
+
+insert into TbBook (title, author, publisher, price, lendcount) values ('Java核心技术(卷1)', '凯 S.霍斯特曼', '机械工业出版社', 98.2, 102);
+insert into TbBook (title, author, publisher, price, lendcount) values ('Java编程思想', '埃史尔', '机械工业出版社', 86.4, 87);
+insert into TbBook (title, author, publisher, price, lendcount) values ('深入理解Java虚拟机', '周志明', '机械工业出版社', 64.4, 32);
+insert into TbBook (title, author, publisher, price, lendcount) values ('Effective Java中文版(第2版) ', '埃史尔', '机械工业出版社', 36.8, 200);
+insert into TbBook (title, author, publisher, price, lendcount) values ('数据结构与算法分析:Java语言描述(原书第3版)', '马克·艾伦·维斯', '机械工业出版社', 51.0, 15);
+insert into TbBook (title, author, publisher, price, lendcount) values ('Java 8实战', '厄马', '人民邮电出版社', 56.8, 25);
+insert into TbBook (title, author, publisher, price, lendcount) values ('重构:改善既有代码的设计', '马丁·福勒', '人民邮电出版社', 53.1, 99);
+insert into TbBook (title, author, publisher, price, lendcount) values ('代码大全(第2版)', '史蒂夫•迈克康奈尔', '电子工业出版社', 53.1, 99);
+insert into TbBook (title, author, publisher, price, lendcount) values ('程序员修炼之道:从小工到专家', '亨特, 托马斯', '电子工业出版社', 45.4, 50);
+insert into TbBook (title, author, publisher, price, lendcount) values ('代码整洁之道', '马丁', '人民邮电出版社', 45.4, 30);
+insert into TbBook (title, author, publisher, price, lendcount) values ('设计模式 可复用面向对象软件的基础', 'Erich Gamma, Richard Helm', '机械工业出版社', 30.2, 77);
+insert into TbBook (title, author, publisher, price, lendcount) values ('设计模式之禅(第2版)', '秦小波', '机械工业出版社', 70.4, 100);
+

+ 186 - 0
Day36-40/code/all/SRS_create_and_init.sql

@@ -0,0 +1,186 @@
+-- 查看MySQL服务器所有数据库
+show databases;
+-- 删除SRS数据库
+drop database if exists SRS;
+-- 创建学生选课系统(SRS)数据库并指定默认字符集
+create database SRS default charset utf8;
+-- 切换至SRS数据库
+use SRS;
+-- 查看当前数据库中所有表
+show tables;
+-- 创建学生表
+create table TbStudent
+(
+stuid integer not null,
+stuname varchar(20) not null,
+stusex bit default 1,
+stubirth datetime not null,
+stutel char(11),
+stuaddr varchar(255),
+stuphoto longblob,
+primary key (stuid)
+);
+-- 修改学生表删除stutel列
+alter table TbStudent drop column stutel;
+-- 查看学生表结构
+desc TbStudent;
+-- 如果表TbCourse已经存在就删除它
+drop table if exists TbCourse;
+-- 创建课程表
+create table TbCourse
+(
+cosid integer not null,
+cosname varchar(50) not null,
+coscredit tinyint not null,
+cosintro varchar(255)
+);
+-- 给课程表指定主键
+alter table TbCourse add constraint pk_course primary key (cosid);
+-- 创建学生选课记录表
+create table TbSC
+(
+scid integer primary key auto_increment,
+sid integer not null,
+cid integer,
+scdate datetime not null,
+score float
+);
+-- 给表TbSC添加外键约束
+alter table TbSC add constraint fk_sid foreign key (sid) references TbStudent (stuid) on delete cascade on update cascade;
+alter table TbSC add constraint fk_cid foreign key (cid) references TBCourse (cosid) on delete set null on update cascade;
+-- 添加学生记录
+insert into TbStudent values (1001, '张三丰', default, '1978-1-1', '成都市一环路西二段17号', null);
+insert into TbStudent (stuid, stuname, stubirth) values (1002, '郭靖', '1980-2-2');
+insert into TbStudent (stuid, stuname, stusex, stubirth, stuaddr) values (1003, '黄蓉', 0, '1982-3-3', '成都市二环路南四段123号');
+insert into TbStudent values (1004, '张无忌', 1, '1990-4-4', null, null);
+insert into TbStudent values 
+(1005, '丘处机', 1, '1983-5-5', '北京市海淀区宝盛北里西区28号', null),
+(1006, '王处一', 1, '1985-6-6', '深圳市宝安区宝安大道5010号', null),
+(1007, '刘处玄', 1, '1987-7-7', '郑州市金水区纬五路21号', null),
+(1008, '孙不二', 0, '1989-8-8', '武汉市光谷大道61号', null),
+(1009, '平一指', 1, '1992-9-9', '西安市雁塔区高新六路52号', null),
+(1010, '老不死', 1, '1993-10-10', '广州市天河区元岗路310号', null),
+(1011, '王大锤', 0, '1994-11-11', null, null),
+(1012, '隔壁老王', 1, '1995-12-12', null, null),
+(1013, '郭啸天', 1, '1977-10-25', null, null);
+-- 删除学生记录
+delete from TbStudent where stuid=1004;
+-- 更新学生记录
+update TbStudent set stubirth='1980-12-12', stuaddr='上海市宝山区同济支路199号' where stuid=1002;
+-- 添加课程记录
+insert into TbCourse values 
+(1111, 'C语言程序设计', 3, '大神级讲师授课需要抢座'),
+(2222, 'Java程序设计', 3, null),
+(3333, '数据库概论', 2, null),
+(4444, '操作系统原理', 4, null);
+-- 添加学生选课记录
+insert into TbSC values 
+(default, 1001, 1111, '2016-9-1', 95),
+(default, 1002, 1111, '2016-9-1', 94),
+(default, 1001, 2222, now(), null),
+(default, 1001, 3333, '2017-3-1', 85),
+(default, 1001, 4444, now(), null),
+(default, 1002, 4444, now(), null),
+(default, 1003, 2222, now(), null),
+(default, 1003, 3333, now(), null),
+(default, 1005, 2222, now(), null),
+(default, 1006, 1111, now(), null),
+(default, 1006, 2222, '2017-3-1', 80),
+(default, 1006, 3333, now(), null),
+(default, 1006, 4444, now(), null),
+(default, 1007, 1111, '2016-9-1', null),
+(default, 1007, 3333, now(), null),
+(default, 1007, 4444, now(), null),
+(default, 1008, 2222, now(), null),
+(default, 1010, 1111, now(), null);
+-- 查询所有学生信息
+select * from TbStudent;
+-- 查询所有课程名称及学分(投影和别名)
+select cosname as `课程名称`, coscredit as `学分` from TbCourse;
+-- 查询所有女学生的姓名和出生日期(筛选)
+select stuname, stubirth from TbStudent where stusex=0;
+-- 查询所有80后学生的姓名、性别和出生日期(筛选)
+select stuname as `姓名`, if(stusex, '男', '女') as `性别`, stubirth as `出生日期`
+from TbStudent where stubirth between '1980-1-1' and '1989-12-31';
+-- 查询姓王的学生姓名和性别(模糊)
+select stuname, stusex from TbStudent where stuname like '王%';
+-- 查询姓郭名字总共两个字的学生的姓名(模糊)
+select stuname from TbStudent where stuname like '郭_';
+-- 查询姓郭名字总共三个字的学生的姓名(模糊)
+select stuname from TbStudent where stuname like '郭__';
+-- 查询名字中有王字的学生的姓名(模糊)
+select stuname from TbStudent where stuname like '%王%';
+-- 查询没有录入家庭住址和照片的学生姓名(多条件筛选和空值处理)
+select stuname from TbStudent where stuaddr is null and stuphoto is null;
+-- 查询学生选课的所有日期(去重)
+select distinct scdate from TbSC;
+-- 查询学生的姓名和生日按年龄从大到小排列(排序)
+select stuname, stubirth from TbStudent order by stubirth;
+-- 查询所有录入了家庭住址的男学生的姓名、出生日期和家庭住址按年龄从小到大排列(多条件筛选和排序)
+select stuname, stubirth, stuaddr from TbStudent where stusex=1 and stuaddr is not null order by stubirth desc;
+-- 查询年龄最大的学生的出生日期(聚合函数)
+select min(stubirth) from TbStudent;
+-- 查询年龄最小的学生的出生日期(聚合函数)
+select max(stubirth) from TbStudent;
+-- 查询男女学生的人数(分组和聚合函数)
+select if(stusex, '男', '女') as `性别`, count(stusex) as `人数` from TbStudent group by stusex;
+-- 查询课程编号为1111的课程的平均成绩(筛选和聚合函数)
+select avg(score) as `平均成绩` from TbSC where cid=1111;
+-- 查询学号为1001的学生所有课程的总成绩(筛选和聚合函数)
+select sum(score) as `总成绩` from TbSC where sid=1001;
+-- 查询每个学生的学号和平均成绩, null值处理成0(分组和聚合函数)
+select sid as `学号`, ifnull(avg(score), 0) as `平均成绩` from TbSC group by sid;
+-- 查询平均成绩大于等于90分的学生的学号和平均成绩
+select sid as `学号`, avg(score) as `平均成绩` from TbSC group by sid having avg(score)>=90;
+
+
+-- 查询年龄最大的学生的姓名(子查询)
+select stuname from TbStudent where stubirth=(select min(stubirth) from TbStudent);
+-- 查询选了两门以上的课程的学生姓名(子查询/分组条件/集合运算)
+select stuname from TbStudent where stuid in 
+(select sid from TbSC group by sid having count(sid)>2);
+-- 查询选课学生的姓名和平均成绩(子查询和连接查询)
+-- 写法1:
+select stuname, avgscore from TbStudent t1 inner join
+(select sid, avg(score) as avgscore from TbSC where score is not null group by sid) t2
+on t1.stuid=t2.sid;
+-- 写法2: 
+select stuname, avgscore from TbStudent t1,
+(select sid, avg(score) as avgscore from TbSC where score is not null group by sid) t2
+where t1.stuid=t2.sid;
+-- 查询学生姓名、所选课程名称和成绩(连接查询)
+-- 写法1:
+select stuname, cosname, score from 
+TbStudent t1, TbCourse t2, TbSC t3
+where t1.stuid=t3.sid and t2.cosid=t3.cid and t3.score is not null;
+-- 写法2:
+select stuname, cosname, score from TbStudent t1 inner join TbCourse t2
+inner join (select sid, cid, score from TbSC where score is not null) t3 
+on t1.stuid=t3.sid and t2.cosid=t3.cid;
+-- 查询每个学生的姓名和选课数量(左外连接和子查询)
+select stuname as `姓名`, ifnull(coscount, 0) as `选课数` from TbStudent t1
+left outer join (select sid, count(sid) as coscount from TbSC group by sid) t2 
+on t1.stuid=t2.sid;
+
+-- 创建系统用户表(演示登录操作和SQL注入攻击)
+create table TbUser
+(
+username varchar(20) primary key,
+userpass varchar(20) not null
+);
+-- 插入用户数据
+insert into TbUser values ('admin', 'admin');
+insert into TbUser values ('hellokitty', '123123');
+
+-- 创建根据学号查询课程平均成绩的存储过程
+drop procedure if exists SpGetAvgScoreByStuId;
+
+create procedure SpGetAvgScoreByStuId(stuId integer, out avgScore float)
+begin 
+    select avg(score) into avgScore from TbSC where sid=stuId;
+end;
+
+-- 调用上面的存储过程
+-- set @stuId=1001;
+call SpGetAvgScoreByStuId(1001, @avgScore);
+select @avgScore as avgScore;

+ 30 - 0
Day36-40/code/all/Shiro_create_and_init.sql

@@ -0,0 +1,30 @@
+drop database if exists shiro;
+create database shiro default charset utf8;
+use shiro;
+
+create table users (
+  id bigint auto_increment,
+  username varchar(100),
+  password varchar(100),
+  password_salt varchar(100),
+  constraint pk_users primary key(id)
+) charset=utf8 ENGINE=InnoDB;
+create unique index idx_users_username on users(username);
+
+create table user_roles(
+  id bigint auto_increment,
+  username varchar(100),
+  role_name varchar(100),
+  constraint pk_user_roles primary key(id)
+) charset=utf8 ENGINE=InnoDB;
+create unique index idx_user_roles on user_roles(username, role_name);
+
+create table roles_permissions(
+  id bigint auto_increment,
+  role_name varchar(100),
+  permission varchar(100),
+  constraint pk_roles_permissions primary key(id)
+) charset=utf8 ENGINE=InnoDB;
+create unique index idx_roles_permissions on roles_permissions(role_name, permission);
+
+insert into users(username,password)values('zhang','123');

+ 46 - 0
Day36-40/code/all/booksys_create_and_init.sql

@@ -0,0 +1,46 @@
+drop database if exists booksys;
+
+create database booksys default charset utf8;
+
+use booksys;
+
+create table tb_book
+(
+bookid integer not null,
+isbn char(13) not null,
+bname varchar(100) not null,
+price decimal(8,2) not null,
+author varchar(100) not null,
+publisher varchar(50) not null,
+pubdate date,
+intro varchar(500),
+lended bit default 0,
+counter integer default 0,
+primary key (bookid)
+);
+
+create table tb_reader
+(
+readerid integer not null,
+rname varchar(20) not null,
+gender bit not null,
+tel char(11) not null,
+birth date,
+regdate date not null,
+available bit default 1,
+primary key (readerid)
+);
+
+create table tb_record
+(
+recordid integer not null auto_increment,
+bid integer not null,
+rid integer not null,
+lenddate datetime not null,
+backdate datetime,
+pulishment decimal(6,2),
+primary key (recordid)
+);
+
+alter table tb_record add constraint fk_record_bid foreign key (bid) references tb_book (bookid) on update cascade;
+alter table tb_record add constraint fk_record_rid foreign key (rid) references tb_reader (readerid) on update cascade;

+ 39 - 0
Day36-40/code/all/mooc_create_and_init.sql

@@ -0,0 +1,39 @@
+drop database if exists mooc1706;
+create database mooc1706 default charset utf8;
+
+use mooc1706;
+
+create table tb_course_catalog
+(
+catid integer not null auto_increment,
+catname varchar(20) not null,
+catparent integer,
+primary key (catid)
+);
+
+alter table tb_course_catalog add constraint fk_catalog_parent 
+foreign key (catparent) references tb_course_catalog(catid) 
+on delete cascade 
+on update cascade;
+
+insert into tb_course_catalog values (default, '前端开发', null);
+insert into tb_course_catalog values (default, '后端开发', null);
+insert into tb_course_catalog values (default, '移动开发', null);
+insert into tb_course_catalog values (default, '数据库', null);
+insert into tb_course_catalog values (default, '云计算&大数据', null);
+insert into tb_course_catalog values (default, '运维&测试', null);
+insert into tb_course_catalog values (default, 'UI设计', null);
+
+
+insert into tb_course_catalog values (default, 'HTML/CSS', 1);
+insert into tb_course_catalog values (default, 'JavaScript', 1);
+insert into tb_course_catalog values (default, 'jQuery', 1);
+insert into tb_course_catalog values (default, 'HTML5', 1);
+insert into tb_course_catalog values (default, 'CSS3', 1);
+insert into tb_course_catalog values (default, 'Node.js', 1);
+insert into tb_course_catalog values (default, 'AngularJS', 1);
+insert into tb_course_catalog values (default, 'Bootstrap', 1);
+insert into tb_course_catalog values (default, 'React', 1);
+insert into tb_course_catalog values (default, 'Sass/Less', 1);
+insert into tb_course_catalog values (default, 'Vue.js', 1);
+insert into tb_course_catalog values (default, 'WebApp', 1);

+ 54 - 0
Day36-40/code/all/sharebike_create_and_init.sql

@@ -0,0 +1,54 @@
+drop database if exists sharebike;
+
+create database sharebike default charset utf8;
+
+use sharebike;
+
+create table tb_city
+(
+    cityid integer not null auto_increment,
+    cityname varchar(20) not null,
+    primary key (cityid)
+);
+
+create table tb_user
+(
+    userid integer not null auto_increment,
+    nickname varchar(50) not null,
+    tel char(11) not null,
+    cityid integer not null,
+    regdate date,
+    primary key (userid)
+);
+
+create table tb_bike
+(
+    bikeid integer not null auto_increment,
+    statecode integer default 0,
+    broken bit default 0,
+    primary key (bikeid)
+);
+
+create table tb_record
+(
+    recordid integer not null auto_increment,
+    userid integer not null,
+    bikeid integer not null,
+    begintime datetime not null,
+    endtime datetime,
+    payway integer,
+    cost float,
+    primary key (recordid)
+);
+
+alter table tb_record add constraint fk_record_userid foreign key (userid) references tb_user (userid);
+
+alter table tb_record add constraint fk_record_bikeid foreign key (bikeid) references tb_bike (bikeid);
+
+select cityname, total from (select cityid, count(cityid) as total from tb_user group by cityid) t1 inner join tb_city t2 on t1.cityid=t2.cityid;
+
+select max(total) from (select userid, count(userid) as total from tb_record group by userid) t1
+
+select nickname, cityname from (select userid, count(userid) as total from tb_record group by userid having total=(select max(total) from (select userid, count(userid) as total from tb_record group by userid) t1)) t2 inner join tb_user as t3 on t2.userid=t3.userid inner join tb_city as t4 on t3.cityid=t4.cityid;
+
+select bikeid, broken from tb_bike 

+ 19 - 0
Day36-40/code/all/shop_create_sql.sql

@@ -0,0 +1,19 @@
+drop database if exists Shop;
+create database Shop default charset utf8;
+use Shop;
+drop table if exists tb_goods;
+create table tb_goods
+(
+gid int not null auto_increment,
+gname varchar(50) not null,
+gprice decimal(10,2) not null,
+gimage varchar(255),
+primary key (gid)
+);
+insert into tb_goods values 
+(default, '乐事(Lay’s)无限薯片', 8.2, 'images/lay.jpg'),
+(default, '旺旺 仙贝 加量装 540g', 18.5, 'images/wang.jpg'),
+(default, '多儿比(Dolbee)黄桃水果罐头', 6.8, 'images/dolbee.jpg'),
+(default, '王致和 精制料酒 500ml', 7.9, 'images/wine.jpg'),
+(default, '陈克明 面条 鸡蛋龙须挂面', 1.0, 'images/noodle.jpg'),
+(default, '鲁花 菜籽油 4L', 69.9, 'images/oil.jpg');

+ 0 - 2
Day36-40/关系型数据库MySQL.md

@@ -343,5 +343,3 @@
 
 1. MySQLdb
 2. PyMySQL
-
-