多表查詢、可視化工具、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);
一.多表查詢
1.笛卡爾積(交叉連接,不使用任何匹配條件)
‘‘‘ # 需求: # 查看每位員工的部門的所有信息 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; ‘‘‘ ‘‘‘ 做了篩選, 結果<=完整數據, 非笛卡爾積 select * from emp, dep where db2.emp.dep_id = db2.dep.id; # 同sql語句上表現是從兩張表拿數據 # 註意: 同時查詢兩張表形成新的表,可以稱之為虛擬表, 原表與表之間可能存在重復字段, 同時使用時需要明確所屬表,必要時還需明確所屬數據庫‘‘‘
mysql> select * from emp,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 | 管理部 | 開車 |
+----+----------+--------+--------+----+-----------+--------+
18 rows in set (0.01 sec)
2.內連接:只連接匹配的行
# 找到兩張表共有的部分相當於利用條件從笛卡爾積結果中篩選出了正確的結果 ‘‘‘ inner join on 內連接:結果為兩張表有對應關系的數據(emp有dep沒有,emp沒有dep有的記錄均不會被虛擬表展示) 語法:左表 inner join 右表 on 兩表有關聯的字段的條件, on就是產生對於關系的(連接的依據) eg:select * from emp inner join dep on emp.dep_id = dep.id; ‘‘‘ mysql> 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 | 市場部 | 銷售 | +----+----------+--------+--------+----+-----------+--------+ 5 rows in set (0.00 sec)
3.左連接:優先顯示左表全部記錄
# 本質:在內連接的基礎上增加左邊有而右邊沒有的結果 ‘‘‘ 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; ‘‘‘ mysql> 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 | +----------+-----------+--------+ 6 rows in set (0.01 sec)
4.右連接:優先顯示右表全部記錄
# 本質:在內連接的基礎上增加右邊有而左邊沒有的結果 ‘‘‘ right join on 右連接:在內連接的基礎上還保留右表特有的記錄 語法:左表 right join 右表 on 兩表有關聯的字段的條件 eg:select * from emp right join dep on emp.dep_id = dep.id; ‘‘‘ ‘‘‘ 在連接語法join 前就是左表, 後就是右表 采用的是left關鍵詞就是左連接, right關鍵詞就是右連接, inner關鍵詞就是內連接 ‘‘‘ mysql> 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 rows in set (0.00 sec)
5.全連接
# 全外連接:在內連接的基礎上增加左邊有右邊沒有的和右邊有左邊沒有的結果 ‘‘‘ 全連接:在內連接的基礎上分別保留這左表及右表特有的記錄 語法: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; ‘‘‘ mysql> 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 | +------+----------+--------+--------+------+-----------+--------+ | 3 | sanjiang | 10 | 1 | 1 | 市場部 | 銷售 | | 5 | liujie | 8 | 1 | 1 | 市場部 | 銷售 | | 1 | egon | 3 | 2 | 2 | 教學部 | 授課 | | 2 | yanghuhu | 2 | 2 | 2 | 教學部 | 授課 | | 4 | owen | 88888 | 2 | 2 | 教學部 | 授課 | | 6 | yingjie | 1.2 | 0 | NULL | NULL | NULL | | NULL | NULL | NULL | NULL | 3 | 管理部 | 開車 | +------+----------+--------+--------+------+-----------+--------+ 7 rows in set (0.00 sec)
‘‘‘ 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; 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; # 分析過程 # 每一個部門 => 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條件關鍵詞之左 ‘‘‘練習
二.navicat可視化工具
‘‘‘ 1. 安裝navicat 2.連接數據庫,並建庫 3.創建表、設置字段、插入數據 4.新建查詢 ‘‘‘
三.python使用mysql(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() ‘‘‘
四.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))
五.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() # 刪 sql2 = ‘delete from user where usr=%s‘ cursor.execute(sql2, ("aaa")) conn.commit() # 改 sql3 = ‘update user set pwd=%s where usr=%s‘ res = cursor.execute(sql3, ("222", "bbb")) conn.commit()
多表查詢、可視化工具、pymysql模塊