zoukankan      html  css  js  c++  java
  • 04 多表查询以及Navicat工具,pymysql模块

    1. 多表查询

    1.1 交叉连接--笛卡儿积

    将两表所有的数据一一对应,生成一张表。 耗内存、资源。

    #表1是主表,表2是从表,
    select * from 表1,表2;	# 连表,全关联,将两张表连在一起(可能有重复字段)
    
    select * from 表1,表2 where 表1.id=表2.pid;  
    #找到两表的对应关系  pid是关联字段
    
    select 表1.name from 表1,表2 where 表1.id=表2.pid and 表1.name="";
    # 筛选
    
    mysql> create table department(
        -> id int,
        -> name varchar(20)
        -> );
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> create table employee(
        -> id int primary key auto_increment,
        -> name varchar(20),
        -> sex enum('male','female') not null default 'male',
        -> age int,
        -> dep_id int
        -> );
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> insert into department values
        -> (200,'技术'),
        -> (201,'人力资源'),
        -> (202,'销售'),
        -> (203,'运营');
    Query OK, 4 rows affected (0.01 sec)
    Records: 4  Duplicates: 0  Warnings: 0
    
    mysql> insert into employee(name,sex,age,dep_id) values
        -> ('egon','male',18,200),
        -> ('alex','female',48,201),
        -> ('wupeiqi','male',38,201),
        -> ('yuanhao','female',28,202),
        -> ('liwenzhou','male',18,200),
        -> ('jingliyang','female',18,204);
    Query OK, 6 rows affected (0.00 sec)
    Records: 6  Duplicates: 0  Warnings: 0
    
    mysql> alter table department rename dep;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> alter table employee rename emp;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> show tables;
    +-----------------+
    | Tables_in_day43 |
    +-----------------+
    | dep             |
    | emp             |
    +-----------------+
    2 rows in set (0.00 sec)
    
    mysql> select * from dep;
    +------+--------------+
    | id   | name         |
    +------+--------------+
    |  200 | 技术         |
    |  201 | 人力资源     |
    |  202 | 销售         |
    |  203 | 运营         |
    +------+--------------+
    4 rows in set (0.00 sec)
    
    mysql> select * from emp;
    +----+------------+--------+------+--------+
    | id | name       | sex    | age  | dep_id |
    +----+------------+--------+------+--------+
    |  1 | egon       | male   |   18 |    200 |
    |  2 | alex       | female |   48 |    201 |
    |  3 | wupeiqi    | male   |   38 |    201 |
    |  4 | yuanhao    | female |   28 |    202 |
    |  5 | liwenzhou  | male   |   18 |    200 |
    |  6 | jingliyang | female |   18 |    204 |
    +----+------------+--------+------+--------+
    6 rows in set (0.00 sec)
    
    mysql> select * from dep,emp;
    +------+--------------+----+------------+--------+------+--------+
    | id   | name         | id | name       | sex    | age  | dep_id |
    +------+--------------+----+------------+--------+------+--------+
    |  200 | 技术         |  1 | egon       | male   |   18 |    200 |
    |  201 | 人力资源     |  1 | egon       | male   |   18 |    200 |
    |  202 | 销售         |  1 | egon       | male   |   18 |    200 |
    |  203 | 运营         |  1 | egon       | male   |   18 |    200 |
    |  200 | 技术         |  2 | alex       | female |   48 |    201 |
    |  201 | 人力资源     |  2 | alex       | female |   48 |    201 |
    |  202 | 销售         |  2 | alex       | female |   48 |    201 |
    |  203 | 运营         |  2 | alex       | female |   48 |    201 |
    |  200 | 技术         |  3 | wupeiqi    | male   |   38 |    201 |
    |  201 | 人力资源     |  3 | wupeiqi    | male   |   38 |    201 |
    |  202 | 销售         |  3 | wupeiqi    | male   |   38 |    201 |
    |  203 | 运营         |  3 | wupeiqi    | male   |   38 |    201 |
    |  200 | 技术         |  4 | yuanhao    | female |   28 |    202 |
    |  201 | 人力资源     |  4 | yuanhao    | female |   28 |    202 |
    |  202 | 销售         |  4 | yuanhao    | female |   28 |    202 |
    |  203 | 运营         |  4 | yuanhao    | female |   28 |    202 |
    |  200 | 技术         |  5 | liwenzhou  | male   |   18 |    200 |
    |  201 | 人力资源     |  5 | liwenzhou  | male   |   18 |    200 |
    |  202 | 销售         |  5 | liwenzhou  | male   |   18 |    200 |
    |  203 | 运营         |  5 | liwenzhou  | male   |   18 |    200 |
    |  200 | 技术         |  6 | jingliyang | female |   18 |    204 |
    |  201 | 人力资源     |  6 | jingliyang | female |   18 |    204 |
    |  202 | 销售         |  6 | jingliyang | female |   18 |    204 |
    |  203 | 运营         |  6 | jingliyang | female |   18 |    204 |
    +------+--------------+----+------------+--------+------+--------+
    24 rows in set (0.00 sec)
    
    mysql> select * from dep,emp where dep.id=emp.dep_id;
    +------+--------------+----+-----------+--------+------+--------+
    | id   | name         | id | name      | sex    | age  | dep_id |
    +------+--------------+----+-----------+--------+------+--------+
    |  200 | 技术         |  1 | egon      | male   |   18 |    200 |
    |  201 | 人力资源      |  2 | alex      | female |   48 |    201 |
    |  201 | 人力资源      |  3 | wupeiqi   | male   |   38 |    201 |
    |  202 | 销售         |  4 | yuanhao   | female |   28 |    202 |
    |  200 | 技术         |  5 | liwenzhou | male   |   18 |    200 |
    +------+--------------+----+-----------+--------+------+--------+
    5 rows in set (0.00 sec)
    
    mysql> select * from dep,emp where dep.id=emp.dep_id and dep.name="技术";
    +------+--------+----+-----------+------+------+--------+
    | id   | name   | id | name      | sex  | age  | dep_id |
    +------+--------+----+-----------+------+------+--------+
    |  200 | 技术   |  1 | egon      | male |   18 |    200 |
    |  200 | 技术   |  5 | liwenzhou | male |   18 |    200 |
    +------+--------+----+-----------+------+------+--------+
    2 rows in set (0.00 sec)
    
    mysql> select dep.id,dep.name from dep,emp where dep.id=emp.dep_id and dep.name="技术";
    +------+--------+
    | id   | name   |
    +------+--------+
    |  200 | 技术   |
    |  200 | 技术   |
    +------+--------+
    2 rows in set (0.00 sec)
    
    mysql>
    

    1.2 连表查询

    ​ 效率最高。

    1. inner join 内连接: 只会显示真正对应的关系,其他无关的都会筛选删除。
    select * from 表1 inner join 表2 on 表1.id=表2.pid; 
    # 对应字段连表
    
    select * from 表1 inner join 表2 on 表1.id=表2.pid where 表2.name="";	
    
    select 表1.name from 表1 inner join 表2 on 表1.id=表2.pid where 表2.name=""; 
    
    mysql> select * from dep inner join emp on dep.id=emp.dep_id;
    +------+--------------+----+-----------+--------+------+--------+
    | id   | name         | id | name      | sex    | age  | dep_id |
    +------+--------------+----+-----------+--------+------+--------+
    |  200 | 技术         |  1 | egon      | male   |   18 |    200 |
    |  201 | 人力资源      |  2 | alex      | female |   48 |    201 |
    |  201 | 人力资源      |  3 | wupeiqi   | male   |   38 |    201 |
    |  202 | 销售         |  4 | yuanhao   | female |   28 |    202 |
    |  200 | 技术         |  5 | liwenzhou | male   |   18 |    200 |
    +------+--------------+----+-----------+--------+------+--------+
    
    mysql> select * from dep inner join emp on dep.id=emp.dep_id where dep.name="技术";
    +------+--------+----+-----------+------+------+--------+
    | id   | name   | id | name      | sex  | age  | dep_id |
    +------+--------+----+-----------+------+------+--------+
    |  200 | 技术   |  1 | egon      | male |   18 |    200 |
    |  200 | 技术   |  5 | liwenzhou | male |   18 |    200 |
    +------+--------+----+-----------+------+------+--------+
    2 rows in set (0.00 sec)
    
    mysql> select emp.name from dep inner join emp on dep.id=emp.dep_id where dep.name="技术";
    +-----------+
    | name      |
    +-----------+
    | egon      |
    | liwenzhou |
    +-----------+
    2 rows in set (0.00 sec)
    
    1. left join 左连接:以左边的表为主表,保证主表的数据全部显示,从表如果没有对应上,用null填充显示。
    select * from 表1 left join 表2 on 表1.id=表2.pid where 表2.name="";	# 表1为主表
    
    mysql> select * from dep left join emp on dep.id=emp.dep_id;                         
    +------+--------------+------+-----------+--------+------+--------+
    | id   | name         | id   | name      | sex    | age  | dep_id |
    +------+--------------+------+-----------+--------+------+--------+
    |  200 | 技术         |    1 | egon      | male   |   18 |    200 |
    |  201 | 人力资源      |    2 | alex      | female |   48 |    201 |
    |  201 | 人力资源      |    3 | wupeiqi   | male   |   38 |    201 |
    |  202 | 销售         |    4 | yuanhao   | female |   28 |    202 |
    |  200 | 技术         |    5 | liwenzhou | male   |   18 |    200 |
    |  203 | 运营         | NULL | NULL      | NULL   | NULL |   NULL |
    +------+--------------+------+-----------+--------+------+--------+
    6 rows in set (0.00 sec)
    
    mysql> select * from dep left join emp on dep.id=emp.dep_id where dep.name="技术";
    +------+--------+------+-----------+------+------+--------+
    | id   | name   | id   | name      | sex  | age  | dep_id |
    +------+--------+------+-----------+------+------+--------+
    |  200 | 技术   |    1 | egon      | male |   18 |    200 |
    |  200 | 技术   |    5 | liwenzhou | male |   18 |    200 |
    +------+--------+------+-----------+------+------+--------+
    2 rows in set (0.00 sec)
    mysql> select emp.name from dep left join emp on dep.id=emp.dep_id where dep.name="技术";
    +-----------+
    | name      |
    +-----------+
    | egon      |
    | liwenzhou |
    +-----------+
    2 rows in set (0.00 sec)
    
    1. right join 右连接:以右边的表为主表,保证主表的数据全部显示,从表如果没有对应上,用NULL填充显示。
    select * from 表1 right join 表2 on 表1.id=表2.pid where 表2.name="";	# 表2为主表
    
    mysql> select * from dep right join emp on dep.id=emp.dep_id;                       
    +------+--------------+----+------------+--------+------+--------+
    | id   | name         | id | name       | sex    | age  | dep_id |
    +------+--------------+----+------------+--------+------+--------+
    |  200 | 技术         |  1 | egon       | male   |   18 |    200 |
    |  200 | 技术         |  5 | liwenzhou  | male   |   18 |    200 |
    |  201 | 人力资源      |  2 | alex       | female |   48 |    201 |
    |  201 | 人力资源      |  3 | wupeiqi    | male   |   38 |    201 |
    |  202 | 销售         |  4 | yuanhao    | female |   28 |    202 |
    | NULL | NULL         |  6 | jingliyang | female |   18 |    204 |
    +------+--------------+----+------------+--------+------+--------+
    6 rows in set (0.00 sec)
    
    1. 全连 union
    select * from 表1 left join 表2 on 表1.id=表2.pid where 表2.name=""  union 
    select * from 表1 right join 表2 on 表1.id=表2.pid where 表2.name="";
    
    mysql> select * from dep left join emp on dep.id=emp.dep_id
        -> union
        -> select * from dep right join emp on dep.id=emp.dep_id;
    +------+--------------+------+------------+--------+------+--------+
    | id   | name         | id   | name       | sex    | age  | dep_id |
    +------+--------------+------+------------+--------+------+--------+
    |  200 | 技术         |    1 | egon       | male   |   18 |    200 |
    |  201 | 人力资源      |    2 | alex       | female |   48 |    201 |
    |  201 | 人力资源      |    3 | wupeiqi    | male   |   38 |    201 |
    |  202 | 销售         |    4 | yuanhao    | female |   28 |    202 |
    |  200 | 技术         |    5 | liwenzhou  | male   |   18 |    200 |
    |  203 | 运营         | NULL | NULL       | NULL   | NULL |   NULL |
    | NULL | NULL         |    6 | jingliyang | female |   18 |    204 |
    +------+--------------+------+------------+--------+------+--------+
    7 rows in set (0.00 sec)
    

    1.3 子查询

    一个表的查询结果作为另一个表的查询条件

    #1:子查询是将一个查询语句嵌套在另一个查询语句中。
    #2:内层查询语句的查询结果,可以为外层查询语句提供查询条件。
    #3:子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
    #4:还可以包含比较运算符:= 、!=、> 、<等
    
    mysql> select name from emp where dep_id = (select id from dep where name = '技术');
    +-----------+
    | name      |
    +-----------+
    | egon      |
    | liwenzhou |
    +-----------+
    2 rows in set (0.01 sec)
    
    1. in 关键字子查询

      #查询员工平均年龄在25岁以上的部门名,可以用连表
      mysql> select dep.name from dep inner join emp on dep.id=emp.dep_id
          -> group by dep.name
          -> having avg(age)>25;
      +--------------+
      | name         |
      +--------------+
      | 人力资源     |
      | 销售         |
      +--------------+
      2 rows in set (0.01 sec)
      
    2. 带比较运算

      #查询大于所有人平均年龄的员工名与年龄
      mysql> select name,age from emp where age >(select avg(age) from emp);
      +---------+------+
      | name    | age  |
      +---------+------+
      | alex    |   48 |
      | wupeiqi |   38 |
      +---------+------+
      2 rows in set (0.01 sec)
      
    3. exists 关键字子查询

      内层查询语句不返回查询的记录。而是返回一个真假值,True或False。当返回True时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询,会显示Empty。

      # dep表中存在id=200,True
      mysql> select * from emp
          -> where exists
          -> (select id from dep where id=200);
      +----+------------+--------+------+--------+
      | id | name       | sex    | age  | dep_id |
      +----+------------+--------+------+--------+
      |  1 | egon       | male   |   18 |    200 |
      |  2 | alex       | female |   48 |    201 |
      |  3 | wupeiqi    | male   |   38 |    201 |
      |  4 | yuanhao    | female |   28 |    202 |
      |  5 | liwenzhou  | male   |   18 |    200 |
      |  6 | jingliyang | female |   18 |    204 |
      +----+------------+--------+------+--------+
      6 rows in set (0.00 sec)
      

    2. Navicat可视化工具

    安装:https://www.cnblogs.com/clschao/articles/10022040.html

    还有专业的 powerDesigner工具

    掌握:
    #1. 测试+链接数据库
    #2. 新建库
    #3. 新建表,新增字段+类型+约束
    #4. 设计表:外键
    #5. 新建查询
    #6. 备份库/表
    
    单行注释: --
    批量注释:ctrl + /
    批量去注释: ctrl + shift + /
    

    3. pymysql模块

    python程序操作mysql的模块,本质是一个套接字客户端。

    3.1 连接查询

    import pymysql
    
    # 连接mysql
    conn = pymysql.connect(host='127.0.0.1', # IP地址
                          port=3306,		 # mysql端口
                          user='root',		 # mysql登录用户名
                          password='123',	 # 密码
                          database='day43',	 # 操作的库
                          charset='utf8'	 # 指定编码,不能写utf-8
                          )
    # 游标 相当于mysql>
    cursor = conn.cursor(pymysql.cursor.DictCursor)
    # 不写,默认游标取出数据是((),(),...)元组形式  里面没有字段名显示
    # DicCursor 显示数据 [{'字段':值},....] 列表套字典的数据形式  
    # 如果用的是fetcheone获取,那么结果是{}
    
    sql = 'select * from dep;'	# 输入sql操作语句
    
    ret = cursor.execute(sql)   # 执行sql语句,返回的是受影响的行数
    print(ret)
    
    print(cursor.fetchall())	# 获取返回的所有数据
    # print(cursor.fetchone())	# 获取出第一条数据
    # print(cursor.fetchmany(3))	# 获取多条(3)数据
    
    """
    取数据时,光标也会向下移动,如果光标移动到最后,再取数据会显示None,
    因此可以移动光标的位置,cursor.scroll(数字,模式)
    """
    cursor.scroll(2, 'absolute')	# absolute 绝对移动,从起始位置开始
    cursor.scroll(2, 'relative')	# 相对移动,从当前光标位置开始
    print(cursor.fetchone())	
    
    # cursor.close()	# 关闭游标
    # conn.close()	# 关闭连接
    

    3.2 增删改 conn.commit() 提交操作

    import pymysql
    
    conn = pymysql.connect(host='127.0.0.1',
                           port=3306,
                           user='root',
                           password='123',
                           database='day43',
                           charset='utf8'
                          )
    
    cursor = conn.cursor(pymysql.cursors.DictCursor)	# 游标
    
    # sql = 'insert into dep(id,name) values(210, "aaa"), (211, "bbb");'
    #ret = cursor.execute(sql)	# 执行sql语句
    
    # 也可以这样写
    sql = 'insert into dep(id,name) values(%s,%s);'
    ret = cursor.executemany(sql,[(212,'ccc'),(213,'ddd')])
    
    print(ret)
    conn.commit()	# 提交操作,如果不提交,数据不会写入到表中
    
    # cursor.close()	# 关闭游标
    # conn.close()		# 关闭连接
    

    3.3 sql 注入

    import pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123',
        database='day43',
        charset='utf8'
    )
    
    username = input('请输入用户名:')
    password = input('请输入密码:')
    
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    
    # sql自己进行字符串拼接  userinfo表自己创建,插入数据
    sql = "select * from userinfo where username='%s' and password=''%s';"%(username,password)
    
    ret = cursor.execute(sql)
    if ret:
        print('登录成功!')
    else:
        print('账户和密码错误!’)
              
    

    注入情况1:不需密码即可登录成功

    # 运行程序
    
    用户名:yan '-- 
    密码:
    登陆成功!
    
    当你输入用户名:  用户名 '--空格 
    提示输入密码时,按回车,会发现登录成功!
    
    解释:
    因为 -- 具有注释的功能,会将后面的密码语句注释掉,不需密码即可登录。
    输入用户名后sql语句变成:
    sql = "select * from userinfo where username='yan '-- ' and password = '%s';"%(username,password)
    # -- 后面的sql语句被注释掉。
    

    注入情况2:不需账户、密码也会登录成功

    # 运行程序
    
    请输入用户名: abc' or 1=1 -- '
    请输入密码: 111
    登陆成功!
    
    请输入用户名: xxx' or 1=1 -- 任意字符串
    请输入密码: 随便输,或者直接回车
    
    解释:
    输入用户名后sql语句变成:
    sql = "select * from userinfo where username='adc' or 1=1 -- ' and password = '%s';"%(username,password)
    
    其中 username='adc' or 1=1 结果永远是True,
    密码后面的又被注释掉
    因此,不需账户、密码就能登录成功!
    

    解决注入造成的数据不安全

    解决思路:
    1.不能使用特殊符号登录,
    2.登录的sql语句不用字符串格式化(拼接)方式
    sql = "select * from userinfo where username='%s' and password=''%s';"%(username,password)
    ret = cursor.execute(sql)
    

    修改sql语句后,再登录,不会出现注入情况。

    import pymysql
    
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='123',
        database='day43',
        charset='utf8'
    )
    
    username = input('请输入用户名:')
    password = input('请输入密码:')
    
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    
    sql="select * from userinfo where username=%s and password=%s;"
    ret=cursor.execute(sql,[username,password]) 
    # 能够将特殊符号过滤掉
    
    ret = cursor.execute(sql)
    if ret:
        print('登录成功!')
    else:
        print('账户和密码错误!’)
    
    
  • 相关阅读:
    odoo 错误 Resource interpreted as Stylesheet but transferred with MIME type application/x-css:
    Android架构师之路-架构到代码的演练
    Android架构师之路-架构师的决策
    EventBus
    Android架构师之路-UML图形思考
    Android架构师之路-oop
    EventBus
    java定义接口监听器详解
    INSTALL_FAILED_NO_MATCHING_ABIS
    android---NDK开发helloworld(jni)
  • 原文地址:https://www.cnblogs.com/yzm1017/p/11455288.html
Copyright © 2011-2022 走看看