日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL——复杂的多表查询——以超市交易数据为例

發布時間:2025/4/5 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL——复杂的多表查询——以超市交易数据为例 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

復雜的多表查詢——以超市交易數據為例

之前的內容基本上都是基于單表進行的查詢操作,但是在實際工作中,數據往往分散在多個表中,這個時候我們就需要用到多表查詢的知識了。

通常來說,多表查詢主要有兩類:一類是縱向的表合并,也就是將結構相同的表上下拼接起來;另一類是橫向的表連接,即將多個表中的字段合并到一張大表中。
(1)縱向表合并
縱向表合并非常好理解,就是把多張相同結構的表按照垂直的方向,將它們進行合并,直白的理解就是上下堆疊(也就是記錄的追加)。下面我們以某超市的經營數據為例,來學習一下縱向表合并。

假設有一個大型連鎖超市,它有很多家加盟店,各個加盟店將不同月份的經營數據存儲在各自的數據表中。每家店數據的存儲方式都相同,也就是字段都一樣,分別為:門店ID、用戶ID(如果沒有辦理會員,則用戶ID為空)、訂單ID、交易日期、應付金額、折扣金額、實付金額以及支付類型。

現在的需求是需要把A、B、C三個超市的交易記錄合并到一張表里面。

縱向合并表需要用到UNION或者UNION ALL關鍵詞,這兩個關鍵詞的功能是一樣的(都是合并操作),但是還是有很大區別的:

  • UNION ALL 在合并表的時候不做任何附加動作,只是將多個表格簡單的首尾相連;
  • UNION 合并表格的時候,除了拼接之外還會多一個附加動作——去重(以前舊版本還有排序功能,新版本舍棄了排序功能)

在性能方面,UNION ALL的合并速度要比UNION 快的多,尤其是數據量比較大的時候,兩者的合并速度差異還是非常明顯的。所以在做縱向表合并的時候,一定要考慮清楚是否需要做去重處理。

# UNION 和 UNION ALL 的區別 SELECT pay_type FROM TransC1805 UNION ALL SELECT pay_type FROM transD1810; SELECT pay_type FROM TransC1805 UNION SELECT pay_type FROM transD1810;

下面嘗試使用UNION ALL 將三張交易表合并成一個表:

SELECT * from TransA1710 UNION ALL SELECT * from TransB1801 UNION ALL SELECT * FROM TransC1805;

當需要合并的表格的字段數量和順序都一樣的時候,這樣寫是沒有問題的。如果其中有一個表的結構不一致(包括數量和排布順序),這樣寫就會出問題了。比如,現在有超市D在2018年10月份的交易數據,但是這個門店在記錄數據的時候,字段順序做了一些調整:

# 如果按照上面的方式合并,得到的結果就會有問題:會按照錯亂的順序直接拼接 SELECT * FROM TransC1805 UNION ALL SELECT * FROM transD1810; # 正確的寫法 SELECT * FROM TransC1805 UNION ALL SELECT shop_id,uid,order_id,date,amt1,amt2,amt3,pay_type FROM transD1810; SELECT shop_id,uid,order_id,idate,amt1,amt2,amt3,pay_type FROM TransC1805 UNION ALL SELECT shop_id,uid,order_id,date,amt1,amt2,amt3,pay_type FROM transD1810;

當要合并的表的字段順序不一致的時候,手動將所有需要的字段都寫出來,并且保證順序一致。

有時候我們并不需要將表中所有記錄和字段都合并,這個時候可以更加靈活使用UNION ALL來完成,比如:將3張表中支付方式為現金(pay_type=1)的交易合并起來,并且保留門店ID、用戶ID、交易訂單號、交易時間和實際交易額信息。

# 將3張表中支付方式為現金(pay_type=1)的交易合并起來,并且保留門店ID、用戶ID、交易訂單號、交易時間和實際交易額信息。 SELECT shop_id,uid,order_id,idate,amt3 from TransA1710 where pay_type=1 UNION ALL SELECT shop_id,uid,order_id,idate,amt3 from TransB1801 where pay_type=1 UNION ALL SELECT shop_id,uid,order_id,idate,amt3 FROM TransC1805 where pay_type=1;

(2)表連接操作
關于表連接操作就稍微有點復雜了,這里會用到各種 JOIN操作,對于初學者來說,特別容易搞混,下面我們通過兩個簡單的數據集來學習一下JOIN連接操作:

CREATE TABLE TA(K INT, V VARCHAR(10)); INSERT INTO TA VALUES (1,"AB"), (2,"A"); SELECT * FROM TA; CREATE TABLE TB(K INT, V VARCHAR(10)); INSERT INTO TB VALUES (1,"AB"), (3,"B"); SELECT * FROM TB;

K=1的記錄在TA和TB兩張表中都有,K=2的記錄為TA表中獨有,K=3的記錄為TB表中獨有。

  • 內連接:INNER JOIN
    內連接就是把兩張表中共有的數據提取出來。

文氏圖:

#內連接 SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA INNER JOIN TB ON TA.K=TB.K;

  • 左連接:LEFT JOIN
    左連接查詢會返回左表(TA)中所有記錄,不管右表中有沒有關聯的數據,如果右表中有關聯的數據會被一并返回(右表中沒有的字段,則以NULL值填充)。
    文氏圖:
#左連接 SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA #左表 LEFT JOIN TB #右表 ON TA.K=TB.K;

  • 右連接:
    右連接查詢會返回右表(TB)中所有記錄,不管左表中有沒有關聯的數據,如果左表中有關聯的數
    據會被一并返回(左表中沒有的字段,則以NULL值填充)
    文氏圖:
#右連接 SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA RIGHT JOIN TB ON TA.K=TB.K;

  • 全連接:FULL OUTER JOIN
    FULL OUTER JOIN 一般稱為全連接或者外連接,實際查詢語句中可以寫作 FULL OUTER JOIN 或 FULL JOIN 。外連接查詢能返回左右表里的所有記錄,其中左右表里能關聯起來的記錄被連接后
    返回。
    文氏圖:
# MySQL中不支持FULL OUTER JOIN,直接使用會報錯 SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA FULL OUTER JOIN TB ON TA.K=TB.K; # 可以使用UNION 模擬全連接返回的結果 SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA LEFT JOIN TB ON TA.K=TB.K UNION SELECT TA.K AS A_K,TB.K AS B_K,TA.V AS A_V,TB.V AS B_V FROM TA RIGHT JOIN TB ON TA.K=TB.K;


以上就是SQL中常見的四種表連接方式了。此外,還有三種延伸用法,大家感興趣的話,可以自行研究一下。

(3)綜合案例——校園一卡通數據的表連接操作
下面我們通過一個綜合案例來學習一下SQL的表連接操作。這里使用的數據是關于校園一卡通的流水記錄,數據來源于DC競賽網,此數據集共包含兩部分,分別是學生的圖書借閱記錄(共包含239947 條數據)和消費記錄(共包含 條數據)。

  • 將數據集導入MySQL中
# 創建學生圖書借閱記錄表 CREATE TABLE stu_borrow (stu_id VARCHAR(10), borrow_date DATE, book_title VARCHAR(500), book_number VARCHAR(50) );# 導入圖書借閱數據 LOAD DATA local INFILE "/Users/zhucan/Desktop/borrow.csv" INTO TABLE stu_borrow FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';# 創建學生的一卡通消費表 CREATE TABLE stu_card( stu_id VARCHAR(10), custom_class VARCHAR(10), custom_add VARCHAR(20), custom_type VARCHAR(20), custom_date DATETIME, amt FLOAT, balance FLOAT );# 導入消費數據 LOAD DATA local INFILE '/Users/zhucan/Desktop/card.txt' INTO TABLE stu_card111 FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
  • 簡單數據探索
    數據全部導入MySQL之后,需要對數據進行探索,了解數據現狀:
# 查詢某位同學的借書記錄 SELECT * FROM stu_borrow WHERE stu_id = '9708' ORDER BY borrow_date;


從返回結果來看,圖書借閱記錄表存在重復記錄,根據實際業務情況,這樣的數據是不應該出現的,所以后續進行數據處理的時候,需要做去重處理。

# 查詢某位學生的消費記錄 SELECT * FROM stu_card WHERE stu_id = '1040' ORDER BY custom_date;


同樣,對于消費記錄來說,也存在重復值,后續數據處理需要做去重操作,并且,消費金額還有復數,這里我們理解為充值行為(因為負的消費金額會導致余額的增加)。

  • 數據處理
    由于兩個表中都有重復值,我們首先對數據集進行統計匯總,確保匯總后的結果使得每個學生對應的記錄只有一條。對于學生來說,一般以學年為單位進行分析,所以我們選擇2014年9月——2015年9月作為統計窗口期。
# 統計2014-9~2015-9學年度每個學生的借書次數以及借閱數量,并將統計結果構成新表 CREATE TABLE borrow_times AS SELECT stu_id ,COUNT(DISTINCT borrow_date) AS borrow_times ,COUNT(DISTINCT book_title) AS books FROM stu_borrow WHERE borrow_date BETWEEN '2014-09-01' AND '2015-08-31' GROUP BY stu_id; # 查看統計結果的前5行 SELECT * FROM borrow_times LIMIT 5;

# 刪除stu_card表中重復記錄以及消費金額為負的記錄,并將清洗結果直接存儲到stu_card_distinct表 中 CREATE TABLE stu_card_distinct AS SELECT DISTINCT * FROM stu_card WHERE amt>0; # 如果運行報錯:Error Code: 1206. The total number of locks exceeds the lock table size # 說明緩存內存不夠(默認為8M),需要設置大一些(比如64M = 64*1024*1024 = 67108864 B) show variables like "%_buffer_pool_size%"; SET GLOBAL innodb_buffer_pool_size=67108864; # 統計2014-9~2015-9學年度每個學生的消費總額,最小金額、最大金額和客單價,并將統計結果直接存儲到custom表中 CREATE TABLE custom AS SELECT stu_id ,COUNT(*) AS custom_times , SUM(amt) AS custom_amt ,MIN(amt) AS min_amt , MAX(amt) AS max_amt ,SUM(amt)/COUNT(*) pct FROM stu_card_distinct WHERE custom_date BETWEEN '2014-09-01' AND '2015-08-31' GROUP BY stu_id;# 查詢統計結果的5行信息 SELECT * FROM custom LIMIT 5;

  • 表連接操作
    將上面處理好的兩張表,整合成一張表。具體選擇何種連接方式,需要根據實際業務需求。
# 統計結果的整合 SELECT COUNT(*) FROM custom; # 共計5427條 SELECT COUNT(*) FROM borrow_times; # 共計4158條 # 學生消費表custom作為主表,圖書借閱表borrow_times作為輔表(左連接) SELECT t1.*, t2.borrow_times,t2.books FROM custom AS t1 LEFT JOIN borrow_times AS t2 ON t1.stu_id = t2.stu_id; # 內連接:提取出兩張表中共有的學生記錄 SELECT t1.*, t2.borrow_times,t2.books FROM custom AS t1 INNER JOIN borrow_times AS t2 ON t1.stu_id = t2.stu_id;


【補充】LOAD DATA的詳細用法

詳細解釋見MySQL用戶手冊《refman-8.0-en.a4.pdf》P2449-P2459

總結

以上是生活随笔為你收集整理的MySQL——复杂的多表查询——以超市交易数据为例的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。