zoukankan      html  css  js  c++  java
  • mysql多表查询

    目录

       1.多表查询 => 转化为一张联合大表

       2.可视化工具
       3.pymysql模块

    多表数据

    create table dep(
        id int primary key auto_increment,
        name varchar(16),
        work varchar(16)
    );
    create table emp(
        id int primary key auto_increment,
        name varchar(16),
        salary float,
        dep_id int
    );
    insert into dep values(1, '市场部', '销售'), (2, '教学部', '授课'), (3, '管理部', '开车');
    insert into emp(name, salary, dep_id) values('egon', 3.0, 2),('yanghuhu', 2.0, 2),('sanjiang', 10.0, 1),('owen', 88888.0, 2),('liujie', 8.0, 1),('yingjie', 1.2, 0);
     

    一、笛卡尔积 (交叉连接)

    # 需求: 
    # 查看每位员工的部门的所有信息
    select * from emp;
    select * from dep;
    ​
    # 子查询, 最终结果只能显示单表的信息, 但需求是同时显示两张表的信息 => 先将两张表合成一张表
    select * from emp where dep_id in (select id from dep);
    ​
    笛卡尔积: 集合 X{a, b} * Y{o, p, q} => Z{{a, o}, {a, p}, {a, q}, {b, o}, {b, p}, {b, q}}
    交叉查询: select * from emp, dep; | select * from emp course join dep;
    +----+----------+--------+--------+----+-----------+--------+
    | id | name     | salary | dep_id | id | name      | work   |
    +----+----------+--------+--------+----+-----------+--------+
    |  1 | egon     |      3 |      2 |  1 | 市场部     | 销售   |
    |  1 | egon     |      3 |      2 |  2 | 教学部     | 授课   |
    |  1 | egon     |      3 |      2 |  3 | 管理部     | 开车   |
    |  2 | yanghuhu |      2 |      2 |  1 | 市场部     | 销售   |
    |  2 | yanghuhu |      2 |      2 |  2 | 教学部     | 授课   |
    |  2 | yanghuhu |      2 |      2 |  3 | 管理部     | 开车   |
    |  3 | sanjiang |     10 |      1 |  1 | 市场部     | 销售   |
    |  3 | sanjiang |     10 |      1 |  2 | 教学部     | 授课   |
    |  3 | sanjiang |     10 |      1 |  3 | 管理部     | 开车   |
    |  4 | owen     |  88888 |      2 |  1 | 市场部     | 销售   |
    |  4 | owen     |  88888 |      2 |  2 | 教学部     | 授课   |
    |  4 | owen     |  88888 |      2 |  3 | 管理部     | 开车   |
    |  5 | liujie   |      8 |      1 |  1 | 市场部     | 销售   |
    |  5 | liujie   |      8 |      1 |  2 | 教学部     | 授课   |
    |  5 | liujie   |      8 |      1 |  3 | 管理部     | 开车   |
    |  6 | yingjie  |    1.2 |      0 |  1 | 市场部     | 销售   |
    |  6 | yingjie  |    1.2 |      0 |  2 | 教学部     | 授课   |
    |  6 | yingjie  |    1.2 |      0 |  3 | 管理部     | 开车   |
    +----+----------+--------+--------+----+-----------+--------+
        
    做了筛选, 结果<=完整数据, 非笛卡尔积
    select * from emp, dep where db2.emp.dep_id = db2.dep.id;  # 同sql语句上表现是从两张表拿数据
    +----+----------+--------+--------+----+-----------+--------+
    | id | name     | salary | dep_id | id | name      | work   |
    +----+----------+--------+--------+----+-----------+--------+
    |  1 | egon     |      3 |      2 |  2 | 教学部     | 授课    |
    |  2 | yanghuhu |      2 |      2 |  2 | 教学部     | 授课    |
    |  3 | sanjiang |     10 |      1 |  1 | 市场部     | 销售    |
    |  4 | owen     |  88888 |      2 |  2 | 教学部     | 授课    |
    |  5 | liujie   |      8 |      1 |  1 | 市场部     | 销售    |
    +----+----------+--------+--------+----+-----------+--------+
    # 注意: 同时查询两张表形成新的表,可以称之为虚拟表, 原表与表之间可能存在重复字段, 同时使用时需要明确所属表,必要时还需明确所属数据库
     

    二、多表连接(*****) => 虚拟的单表

    1、内连接

    inner join on
    内连接:结果为两张表有对应关系的数据(emp有dep没有,emp没有dep有的记录均不会被虚拟表展示)
    语法:左表 inner join 右表 on 两表有关联的字段的条件, on就是产生对于关系的(连接的依据)
    eg:select * from emp inner join dep on emp.dep_id = dep.id;
    +----+----------+--------+--------+----+-----------+--------+
    | id | name     | salary | dep_id | id | name      | work   |
    +----+----------+--------+--------+----+-----------+--------+
    |  1 | egon     |      3 |      2 |  2 | 教学部     | 授课    |
    |  2 | yanghuhu |      2 |      2 |  2 | 教学部     | 授课    |
    |  3 | sanjiang |     10 |      1 |  1 | 市场部     | 销售    |
    |  4 | owen     |  88888 |      2 |  2 | 教学部     | 授课    |
    |  5 | liujie   |      8 |      1 |  1 | 市场部     | 销售    |
    +----+----------+--------+--------+----+-----------+--------+
     

    2、左连接

    left join on
    左连接:在内连接的基础上还保留左表特有的记录
    语法:左表 left join 右表 on 两表有关联的字段的条件
    ​
    eg:select emp.name '员工', dep.name '部门', dep.work '职责' from emp left join dep on emp.dep_id = dep.id;
    +----------+-----------+--------+
    | 员工      | 部门      | 职责    |
    +----------+-----------+--------+
    | sanjiang | 市场部     | 销售   |
    | liujie   | 市场部     | 销售   |
    | egon     | 教学部     | 授课   |
    | yanghuhu | 教学部     | 授课   |
    | owen     | 教学部     | 授课   |
    | yingjie  | NULL      | NULL   |
    +----------+-----------+--------+

     

    3、右连接

    right join on
    右连接:在内连接的基础上还保留右表特有的记录
    语法:左表 right join 右表 on 两表有关联的字段的条件
    eg:select * from emp right join dep on emp.dep_id = dep.id;
    +------+----------+--------+--------+----+-----------+--------+
    | id   | name     | salary | dep_id | id | name      | work   |
    +------+----------+--------+--------+----+-----------+--------+
    |    1 | egon     |      3 |      2 |  2 | 教学部     | 授课   |
    |    2 | yanghuhu |      2 |      2 |  2 | 教学部     | 授课   |
    |    3 | sanjiang |     10 |      1 |  1 | 市场部     | 销售   |
    |    4 | owen     |  88888 |      2 |  2 | 教学部     | 授课   |
    |    5 | liujie   |      8 |      1 |  1 | 市场部     | 销售   |
    | NULL | NULL     |   NULL |   NULL |  3 | 管理部     | 开车   |
    +------+----------+--------+--------+----+-----------+--------+
    
    
    在连接语法join 前就是左表, 后就是右表
    采用的是left关键词就是左连接, right关键词就是右连接, inner关键词就是内连接

    4、全连接

    全连接:在内连接的基础上分别保留这左表及右表特有的记录
    语法:mysql没有full join on语法,但可以通过去重达到效果
    eg:
    select * from emp left join dep on emp.dep_id = dep.id
    union
    select * from emp right join dep on emp.dep_id = dep.id;
    +------+----------+--------+--------+------+-----------+--------+
    | id   | name     | salary | dep_id | id   | name      | work   |
    +------+----------+--------+--------+------+-----------+--------+
    |    1 | egon     |      3 |      2 |    2 | 教学部     | 授课    |
    |    2 | yanghuhu |      2 |      2 |    2 | 教学部     | 授课    |
    |    3 | sanjiang |     10 |      1 |    1 | 市场部     | 销售    |
    |    4 | owen     |  88888 |      2 |    2 | 教学部     | 授课    |
    |    5 | liujie   |      8 |      1 |    1 | 市场部     | 销售    |
    | NULL | NULL     |   NULL |   NULL |    3 | 管理部     | 开车    |
    |    6 | yingjie  |    1.2 |      0 | NULL | NULL      | NULL   |
    +------+----------+--------+--------+------+-----------+--------+

     

    练习

    1.查询每一位员工对应的工作职责
    # 每一位员工 => 左表为emp表, 那么左表的所有数据均需要被保留, 所有采用左连接
               => 左表为dep表, 那么右表的所有数据均需要被保留, 所有采用右连接
    # select emp.name, dep.work from emp left join dep on emp.dep_id = dep.id;
    select emp.name, dep.work from dep right join emp on emp.dep_id = dep.id;
    +----------+--------+
    | name     | work   |
    +----------+--------+
    | sanjiang | 销售   |
    | liujie   | 销售   |
    | egon     | 授课   |
    | yanghuhu | 授课   |
    | owen     | 授课   |
    | yingjie  | NULL   |
    +----------+--------+2.查询每一个部门下的员工们及员工职责
    # select max(dep.name), max(dep.work), group_concat(emp.name) from emp right join dep on emp.dep_id = dep.id group by dep_id;
    +---------------+---------------+------------------------+
    | max(dep.name) | max(dep.work) | group_concat(emp.name) |
    +---------------+---------------+------------------------+
    | 管理部         | 开车          | NULL                   |
    | 市场部         | 销售          | liujie,sanjiang        |
    | 教学部         | 授课          | yanghuhu,owen,egon     |
    +---------------+---------------+------------------------+# 分析过程
    # 每一个部门 => dep的信息要被全部保留, 需要分组
    # 员工职责 => dep.work, 由于分组不能直接被查询 => 需要用聚合函数处理
    # 员工们 => emp.name做拼接 => group_concat(emp.name)
    # 分组的字段 => 部门 => emp.dep_id => emp.dep_id可以直接被查询,但没有显示意义 => dep.name用来显示 => dep.name需要用聚合函数处理
    ​
    ​
    select max(dep.name), max(dep.work), group_concat(emp.name) from dep left join emp on  emp.dep_id = dep.id group by emp.dep_id;
    ​
    # 注: on在where条件关键词之左

    三、pymysql模块

    1.基本操作:连接 -> 设置游标 -> 执行sql -> 提交或获取结果 -> 关闭游标与连接
    2.游标设置:pymysql.cursors.DictCursor
    3.游标取值与偏移:fetchone() | fetchmany(n) | scroll(n,'relative|absolute')
    4.防注入:cursor.execute('select * from user where usr=%s and pwd=%s', (usr, pwd))
    5.提交操作结果:conn.commit()
    ​
    # 模块pymysql
    # 按照并导入pymysql: pip3 insatll pymysql
    # 通过pymysql操作数据库分四步:
    1.建立连接
    conn = pymysql.connect(host="localhost", port=3306, db='db2', user='root', password='root')
    ​
    2.设置字典类型游标
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    ​
    3.执行sql语句并使用执行结果
    ​
    # 书写sql语句
    sql = 'select * from emp'
    # 执行sql语句, 有返回值, 返回值为得到的记录行数
    line = cursor.execute(sql)
    print(line)
    ​
    # 使用执行的结果: 
            fetchone())当前游标往后获取一行记录 
            fetchall()当前游标往后所有的记录
            scroll(num, mode="relative|absolute")
                    relative: 游标从当前位置往后移动num行
                    ablolute: 游标从头往后移动num行, 一般可以结合line来使用能定位到任意位置
    tag = cursor.fetchone() # 第一条
    print(tag)
    print(tag['salary'])
    tag = cursor.fetchone() # 第二条
    print(tag)
    cursor.scroll(1, mode='relative') # 偏移第三条
    # cursor.scroll(line - 1, mode='absolute') # 指针绝对, 游标永远从头开始偏移
    tags = cursor.fetchall() # 第四条到最后
    print(tags)
    ​
    4.断开连接
    cursor.close()
    conn.close()

    1、pymysql处理了sql注入

    # 什么是sql注入:
    # 通过书写sql包含(注释相关的)特殊字符, 让原有的sql执行顺序发生改变, 从而改变执行得到的sql
    # 目的:
    # 绕过原有的sql安全认证, 达到对数据库攻击的目的
    # 没有处理sql注入的写法
    sql = 'select * from user where usr="%s" and pwd="%s"' % (usr, pwd)
    res = cursor.execute(sql)
    ​
    # sql注入
    # 1.知道用户名:  abc" -- hehe | ooo
    # select * from user where usr="abc" -- hehe" and pwd="ooo"
    # 2.不知道用户名 aaa" or 1=1 -- hehe | 000
    # select * from user where usr="aaa" or 1=1 -- hehe" and pwd="000"
    # 处理sql注入
    sql = 'select * from user where usr=%s and pwd=%s'
    res = cursor.execute(sql, (usr, pwd))

     

    2、pymysql中增删改

    #
    # 增sql语句
    sql1 = 'insert into user(usr, pwd) values (%s, %s)'
    # 在内存中一次插入一条
    cursor.execute(sql1, ("opq", "123"))
    # 在内存中一次插入多条
    cursor.executemany(sql1, [("aaa", "000"), ("bbb", "111")])
    # 将内存中的数据提交到硬盘中
    conn.commit()

     

  • 相关阅读:
    hdu 1176 免费馅饼
    算法竞赛入门经典训练指南-做题详细记录(更新中)
    poj-3250 Bad Hair Day
    poj-2823 Sliding Window
    2019.7.15-7.20暑假集训总结
    hdu 1754 I hate it
    poj 1611 The Suspects
    hdu 3038 How Many Answers Are Wrong
    hdu 1213 How Many Tables
    POJ 1182 食物链
  • 原文地址:https://www.cnblogs.com/peng-zhao/p/10257135.html
Copyright © 2011-2022 走看看