多表联合查询、脚本使用pymysql

一、多表联合查询

1、数据准备 

部门表和员工表

create table dep(
    id int primary key auto_increment,
    name varchar(20) 
);

create table emp(
    id int primary key auto_increment,
    name varchar(20),
    sex enum('male','female') not null default 'male',
    age int,
    dep_id int
);

插入数据

insert into dep values
(200,'技术'),
(201,'人力资源'),
(202,'销售'),
(203,'运营'),
(205,'保洁');

insert into emp(name,sex,age,dep_id) values
('jason','male',18,200),
('egon','female',48,201),
('kevin','male',18,201),
('nick','male',28,202),
('owen','male',18,203),
('jerry','female',18,204);

2、多表查询

子查询

一条SQL语句的执行结果当成另外一条SQL语句的执行条件

问题:查看员工jason的部门名称:

select dep_id from emp where name='jason';

select * from dep where id=200;

把上述两条SQL语句合并为一条SQL语句

select * from dep where id= (select dep_id from emp where name='jason');

连表查询

把多张实际存在的表按照表关系连成一张虚拟表(不是实际存在的表,而是临时在内存中存的)

select * from emp,dep where emp.dep_id=dep.id;

联表的专业语法

inner join # 内连接,数据只取两张表中共有的数据

left join # 左连接,数据以左表为准,展示左表所有的数据,右表没有的数据使用NULL填充

right join # 右连接,数据以右表为准,展示右表所有的数据,左表没有的数据使用NULL填充

union # 连接多条SQL语句执行的结果

1. inner join

> select * from emp inner join dep where emp.dep_id = dep.id;

+----+-------+--------+-----+--------+-----+----------+
| id | name  | sex    | age | dep_id | id  | name     |
+----+-------+--------+-----+--------+-----+----------+
| 1  | jason | male   | 18  | 200    | 200 | 技术     |
| 2  | egon  | female | 48  | 201    | 201 | 人力资源 |
| 3  | kevin | male   | 18  | 201    | 201 | 人力资源 |
| 4  | nick  | male   | 28  | 202    | 202 | 销售     |
| 5  | owen  | male   | 18  | 203    | 203 | 运营     |
+----+-------+--------+-----+--------+-----+----------+

2. left join

>  select * from emp left join dep on  emp.dep_id = dep.id;

+----+-------+--------+-----+--------+--------+----------+
| id | name  | sex    | age | dep_id | id     | name     |
+----+-------+--------+-----+--------+--------+----------+
| 1  | jason | male   | 18  | 200    | 200    | 技术     |
| 2  | egon  | female | 48  | 201    | 201    | 人力资源 |
| 3  | kevin | male   | 18  | 201    | 201    | 人力资源 |
| 4  | nick  | male   | 28  | 202    | 202    | 销售     |
| 5  | owen  | male   | 18  | 203    | 203    | 运营     |
| 6  | jerry | female | 18  | 204    | <null> | <null>   |
+----+-------+--------+-----+--------+--------+----------+

3. right join

> select * from emp right join dep  on  emp.dep_id = dep.id;

+--------+--------+--------+--------+--------+-----+----------+
| id     | name   | sex    | age    | dep_id | id  | name     |
+--------+--------+--------+--------+--------+-----+----------+
| 1      | jason  | male   | 18     | 200    | 200 | 技术     |
| 3      | kevin  | male   | 18     | 201    | 201 | 人力资源 |
| 2      | egon   | female | 48     | 201    | 201 | 人力资源 |
| 4      | nick   | male   | 28     | 202    | 202 | 销售     |
| 5      | owen   | male   | 18     | 203    | 203 | 运营     |
| <null> | <null> | <null> | <null> | <null> | 205 | 保洁     |
+--------+--------+--------+--------+--------+-----+----------+

4. union

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   | sex    | age    | dep_id | id     | name     |
+--------+--------+--------+--------+--------+--------+----------+
| 1      | jason  | male   | 18     | 200    | 200    | 技术     |
| 2      | egon   | female | 48     | 201    | 201    | 人力资源 |
| 3      | kevin  | male   | 18     | 201    | 201    | 人力资源 |
| 4      | nick   | male   | 28     | 202    | 202    | 销售     |
| 5      | owen   | male   | 18     | 203    | 203    | 运营     |
| 6      | jerry  | female | 18     | 204    | <null> | <null>   |
| <null> | <null> | <null> | <null> | <null> | 205    | 保洁     |
+--------+--------+--------+--------+--------+--------+----------+

还可以起别名

select * from emp as e inner join dep as d on e.dep_id=d.id;

二、脚本中使用 pymysql

1、借助于第三方模块操作MySQL

pymysql
mysqlclient----->非常好用,一般情况下很难安装成功
mysqldb

2、安装模块

pip install pymysql;

3、实操模版

import pymysql

# 1 连接mysql服务端
conn = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    password='Zjz5740##',
    db='data2',
    charset='utf8',
    autocommit=True
)
# 2 获取游标
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

# 3 执行sql语句
# sql = "insert into emp(name, sex, age, hire_date) values('kevin','male',18, NOW())"
sql = "select * from emp"
# 4 开始执行
affect_rows = cursor.execute(sql)
# print(affect_rows)

# conn.commit()  # 修改、添加数据需要commit

# 5 拿到具体数据
# print(cursor.fetchall())
for i in cursor.fetchall():
    print(i)

# 6 关闭游标、连接
cursor.close()
conn.close() 

注⚠️:cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)中

pymysql.cursors.DictCursor是PyMySQL库提供的一个游标(cursor)类。它用于创建一个游标对象,该对象以字典形式返回查询结果,而不是默认的元组形式。

而默认是 cursor = conn.cursor() 这种方式创建的游标对象,查询结果以元组的形式返回,其中每个元素对应结果中的一个字段的值。

import pymysql

conn = pymysql.connect(host='localhost', user='user', password='password', database='mydb')
cursor = conn.cursor()

cursor.execute("SELECT * FROM users")
row = cursor.fetchone()
print(row[0])

大元组套小元组,一个小元组就是一条记录

4、简易登录注册代码使用mysql作为数据库

import pymysql

# 连接数据库
conn = pymysql.connect(
    host='localhost',
    user='root',
    password='Zjz5740##',
    database='atm'
    autocommit=True  # 针对增 改 删自动二次确认
)

# 注册函数
def register():
    # 获取用户输入的用户名和密码
    username = input("请输入用户名: ")
    password = input("请输入密码: ")

    # 查询用户是否已存在
    cursor = conn.cursor()
    sql = "SELECT * FROM user WHERE name = %s"  # 避免了sql注入
    cursor.execute(sql, (username,))
    result = cursor.fetchone()

    if result:
        print("该用户名已存在,请重新注册!")
    else:
        # 执行插入语句,将用户信息写入数据库
        insert_sql = "INSERT INTO user (name, password) VALUES (%s, %s)"
        cursor.execute(insert_sql, (username, password))
        conn.commit()
        print("注册成功!")
    cursor.close()

# 登录函数
def login():
    # 获取用户输入的用户名和密码
    username = input("请输入用户名: ")
    password = input("请输入密码: ")

    # 查询用户是否存在
    cursor = conn.cursor()
    sql = "SELECT * FROM user WHERE name = %s AND password = %s"
    cursor.execute(sql, (username, password))
    result = cursor.fetchone()

    if result:
        print("登录成功!")
    else:
        print("用户名或密码错误!")

    cursor.close()

# 主菜单
def main_menu():
    while True:
        print("1. 注册")
        print("2. 登录")
        print("3. 退出")

        choice = input("请选择操作: ")

        if choice == '1':
            register()
        elif choice == '2':
            login()
        elif choice == '3':
            break
        else:
            print("无效的选择,请重新输入!")

# 执行主菜单
main_menu()

# 关闭数据库连接
conn.close()    

sql 注入

  1. 基于布尔逻辑的注入:攻击者利用布尔逻辑判断条件,通过构造恶意输入来绕过验证逻辑。例如,在登录页面的用户名和密码字段中输入 ' OR '1'='1,攻击者可以成功绕过验证逻辑,因为这个输入会使SQL查询的条件始终为真。

  2. 基于注释的注入:攻击者使用注释符号(例如--)注释掉原始SQL查询的一部分,然后在注释之后添加自己的恶意代码。这样,攻击者可以在注释符号后执行任意的SQL代码。

  3. UNION注入:攻击者利用UNION操作符将恶意查询结果合并到原始查询中。通过构造恶意的UNION查询,攻击者可以从其他表中提取数据,甚至是敏感信息

import pymysql

conn = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    passwd='Z740##',
    database='atm',
    charset='utf8mb4',
    autocommit=True
)

cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

username = input('用户名:').strip()
password = input('密码:').strip()

sql = "select * from user where  name='%s' and password='%s' " % (username, password)

print(sql)

affect_rows = cursor.execute(sql)

res = cursor.fetchone()

if res:
    print('登录成功')
else:
    print('登录失败')

第一种是使用-- 把密码那一部分的sql语句给注释掉了

第二种是‘ or 1=’1,把password设置为空,接上一个or 1=‘1’

 5、修改mysql数据库库名、表名大写为小写案例

import pymysql

# MySQL 数据库配置
config = {
    'user': 'root',
    'password': 'password',
    'host': 'ip',
    'port': 3306,
    'cursorclass': pymysql.cursors.DictCursor,
}

db = None  # 初始化 db 为 None

try:
    # 连接数据库,创建 cursor 对象
    db = pymysql.connect(**config)
    cursor = db.cursor()
    cursor.execute("SHOW DATABASES")
    databases = cursor.fetchall()

    for database in databases:
        db_name = database['Database']
        if db_name in ['information_schema', 'performance_schema', 'mysql', 'sys']:
            continue
        # 库名为大写的情况
        if any(c.isupper() for c in db_name):
            new_db_name = db_name.lower()  # 转换为小写

            # 创建新数据库
            cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{new_db_name}`")
            print(f'Created database {new_db_name}')

            # 切换到当前数据库
            db.select_db(db_name)
            # 获取当前数据库中的所有表
            cursor.execute(f"SHOW TABLES IN {db_name}")
            tables = cursor.fetchall()
            for table in tables:
                table_name = table[f'Tables_in_{db_name}']
                new_table_name = table_name.lower()
                cursor.execute(f"RENAME TABLE `{db_name}`.`{table_name}` TO `{new_db_name}`.`{new_table_name}`")
                print(f'Renamed table {table_name} to {new_table_name} in database {new_db_name}')
        # 库名为小写的情况
        else:
            db.select_db(db_name)
            cursor.execute(f"SHOW TABLES IN {db_name}")
            tables = cursor.fetchall()
            for table in tables:
                table_name = table[f'Tables_in_{db_name}']
                if any(c.isupper() for c in table_name):
                    new_table_name = table_name.lower()
                    cursor.execute(f"RENAME TABLE `{db_name}`.`{table_name}` TO `{db_name}`.`{new_table_name}`")
                    print(f'Renamed table {table_name} to {new_table_name} in database {db_name}')
except pymysql.Error as e:
    print(f"Error connecting to MySQL Platform: {e}")
finally:
    if db:
        db.close()

  

 

posted @ 2023-07-13 16:50  凡人半睁眼  阅读(44)  评论(0编辑  收藏  举报