一文帶你用 SQL 征服數學建模數據處理

一文帶你領略 SQL 的強大

1. SQL 簡介

SQL (Structured Query Language:結構化查詢語言) 是用於用於管理關係數據庫管理系統(RDBMS)。 SQL 的範圍包括數據插入、查詢、更新和刪除,數據庫模式創建和修改,以及數據訪問控制。

2.優勢

​ SQL 面向數據庫進行 增刪查改,在我們沒有接觸數據庫的時候,如果要對數據進行處理,一般會用到 for 循環進行遍歷。比如,我們有一個結構體數組(下文稱爲表),裏面包含着名字,年齡和性別。如果我們要把性別爲女的同學查找出來,我們需要使用 for 循環一遍,訪問每一個結構體中的性別,進行甄別。這種方法對於幾百幾千條數據來說耗費時間看似沒有差別,但如果是幾十萬,幾百萬條數據,時間的耗費則越來越重。

​ 再者,如果存在另外一個表,裏面記錄着每一同學每次考試的成績,我們現在需要將兩個表進行合併,成爲一條包含着名字,性別,年齡以及成績(假設名字唯一)的數據,這時我們就需要使用兩個 for 循環來處理,並構造新的結構體來進行存儲,即便其他語言比如 Python 等 不需要構造結構體,但兩層的 for 循環帶來的時間耗費的提高也是不容小覷的,更何況會存在更多層 for 循環的情形

​ 筆者曾參加過 2020年 的數模國賽,選擇的就是大數據問題,說實話,當時沒有用到過數據庫,用的雖然是 Python 但 處理數據的時候,使用了許多 for 循環,耗費了許多時間,只水了個省二。貼一下當時處理處理數據的一小部分代碼,可以看出,不僅數據量大而且處理邏輯複雜,還很容易出錯。比賽完之後就覺得如果使用數據庫來進行處理,定會有奇效的。果然,幾分鐘 for 纔得到的數據 SQL 一兩秒秒了。所以筆者很推薦準備參加數學建模並且選擇大數據題目的同學,加強一下數據庫的學習以及練習。

# Dep_In_Profit 企業進貨稅價和
# Dep_In_Price  企業進貨價格和
# Dep_In_Rex  企業進貨稅收和
# Dep_In_Tic_T 企業進貨有效發票
# Dep_In_Tic_T_R 負數票據
# Dep_In_Tic_T_S 正數票據
# Dep_In_Tic_F 企業進貨無效發票
Dep_In_Profit_M = np.zeros(302)
Dep_In_Price_M = np.zeros(302)
Dep_In_Rex_M  = np.zeros(302)
Dep_In_Profit_N = np.zeros(302)
Dep_In_Price_N = np.zeros(302)
Dep_In_Rex_N  = np.zeros(302)
Dep_In_Tic_T = np.zeros(302)
Dep_In_Tic_F = np.zeros(302)
Dep_In_Tic_T_R = np.zeros(302)
Dep_In_Tic_T_S = np.zeros(302)
for i in range(0,395175):
    if In_items.iloc[i,9] == 1:
        Dep_In_Tic_T[In_items.iloc[i, 8]-124] = Dep_In_Tic_T[In_items.iloc[i, 8]-124] + 1
        if In_items.iloc[i, 6] < 0:
            Dep_In_Profit_N[In_items.iloc[i, 8]-124] = Dep_In_Profit_N[In_items.iloc[i, 8]-124] + In_items.iloc[i, 6]
            Dep_In_Price_N[In_items.iloc[i, 8]-124] = Dep_In_Price_N[In_items.iloc[i, 8]-124] + In_items.iloc[i, 4]
            Dep_In_Rex_N[In_items.iloc[i, 8]-124] = Dep_In_Rex_N[In_items.iloc[i, 8]-124] + In_items.iloc[i, 5]
            Dep_In_Tic_T_R[In_items.iloc[i, 8]-124] = Dep_In_Tic_T_R[In_items.iloc[i, 8]-124] + 1
        else:   
            Dep_In_Profit_M[In_items.iloc[i, 8]-124] = Dep_In_Profit_M[In_items.iloc[i, 8]-124] + In_items.iloc[i, 6]
            Dep_In_Price_M[In_items.iloc[i, 8]-124] = Dep_In_Price_M[In_items.iloc[i, 8]-124] + In_items.iloc[i, 4]
            Dep_In_Rex_M[In_items.iloc[i, 8]-124] = Dep_In_Rex_M[In_items.iloc[i, 8]-124] + In_items.iloc[i, 5]
            Dep_In_Tic_T_S[In_items.iloc[i, 8]-124] = Dep_In_Tic_T_S[In_items.iloc[i, 8]-124] + 1
    else:
        Dep_In_Tic_F[In_items.iloc[i, 8]-124] = Dep_In_Tic_F[In_items.iloc[i, 8]-124] + 1

3.用武之處

​ 首先是數學建模以及大數據處理方面的應用,當然這方面的應用是 SQL 相較於一般處理方法的優勢所在,並且在處理多表級聯關係時,SQL 顯得更加簡潔,for 循環或其他一般方式顯得更加複雜以及更容易出錯。

​ 其次在應用開發時,無論是 web 應用還是移動端 ,數據庫肯定是需要的,用於前後端數據的聯繫,雖然平時並不會設計很大的數據量,但熟悉 SQL 的基本增刪改查也是很有必要噠。

4.入門

1. 增
1.1 增加數據庫
create database learn; # learn 爲數據庫的名稱 
use learn; # 使用此數據庫
set names utf8; # 設置編碼
1.2 增加表
CREATE TABLE Persons # 括號裏包含着每一個鍵的名稱以及數據類型用逗號隔開
(
    PersonID  int,
    LastName  varchar(255),
    FirstName varchar(255),
    Address   varchar(255),
    City      varchar(255)
    # 可在定義之後加上一些約束,之後會提到
);
1.3 增加表中的數據
1.3.1 插入整條數據
insert into Persons # 插入整條數據的時候要與表中的鍵一一對應 
values (1, 'mary', 'Smith', '127.0.0.1', 'Beijing');
insert into Persons
values (3, 'mar', 'Smith', '127.0.4.1', 'Beijing');
insert into Persons
values (4, 'max', 'Smith', '127.0.6.1', 'Tianjin');
insert into Persons
values (5, 'mute', 'Rio', '127.0.6.1', 're');
insert into Persons
values (6, 'mate', 'Linda', '127.1.6.1', 'Tianjin');
insert into Persons
values (2, 'mario', 'Smith', '127.1.0.1', 'Nanjing');
1.3.2 插入指定鍵的數據
INSERT INTO Persons (PersonID,LastName,City) # 括號中的便是 表中的鍵 下面插入的 value 需要與之對應
VALUES ('mirry','Smith','Hangzhou');
2. 刪
2.1 刪除數據庫
drop database learn; # 刪庫需謹慎
2.2 刪除表
drop TABLE website; # 刪除表
TRUNCATE TABLE table_name # 刪除表的數據,表本身存在
2.3 刪除索引
ALTER TABLE table_name DROP INDEX index_name; # 適用於MySQL 
DROP INDEX index_name; # 適用於 DB2/Oracle
DROP INDEX table_name.index_name; # 適用於 MS SQL Server
3. 改
3.1 表中增加列
ALTER TABLE table_name 				# 需要指定 表的名稱,列的名稱 以及 數據類型
ADD column_name datatype

alter table ts
add sex nvarchar(10);
3.2 表中刪除列
ALTER TABLE table_name         		# 需要指定 表的名稱,列的名稱
DROP COLUMN column_name

alter table ts
drop column sex;
3.3 表中修改列的數據類型
# SQL Server / MS Access 適用
ALTER TABLE table_name         		# 需要指定 表的名稱,列的名稱,列要修改成的數據類型	
ALTER COLUMN column_name datatype

# My SQL / Oracle 適用
ALTER TABLE table_name				# 需要指定 表的名稱,列的名稱,列要修改成的數據類型	
MODIFY COLUMN column_name datatype

alter table ts
modify column sex nvarchar(100);
4. 查
4.1 查詢所有記錄
select * 				# * 便是指代所有鍵
from Persons;
4.2 查詢指定行的記錄
# 先指定數據庫
use learn;
select PersonID,City from Persons;
# 直接訪問
select PersonID,City from learn.Persons;
4.3 查詢數據庫
show databases;
4.4 查詢數據庫中表的名稱
show tables;
5. 主鍵,外鍵,UNIQUE 約束

​ 主鍵是約束標識表中每一條記錄的,就相當於我們的身份證,不能爲 NULL , 也不能重複,在插入數據的時候必須爲之指定,每一個表都有且僅有一個主鍵。

create table ts(
    id int,
    name varchar(25),
    primary key (id) # 指定主鍵 
);

​ 外鍵是一個表指向另一個表中的 UNIQUE KEY(唯一約束的鍵),假設有 每個班任課老師的表 和 每個教職工的表 這兩張表。

班級任課老師表

任課老師教職工號(外鍵) 老師 班級
03 C 二班
01 A 一班
03 C 三班
02 B 四班

教職工表

老師 教職工號(主鍵)
C 03
B 02
A 01

​ 班級任課老師表中的 任課老師教職工號 指向 教職工表的教職工號。

​ 因此,教職工號作爲 教職工的主鍵(PRIMARY KEY),任課老師教職工號 作爲 班級任課老師表 的 外鍵(FOREIGN KEY)。

# 適用於 MySQL
CREATE TABLE TS
(
    id int NOT NULL,
    name varchar(25),
    P_Id int,
    primary key (id), # 指定主鍵 
    FOREIGN KEY (P_Id) REFERENCES TES(P_Id)
)
# 適用於SQL Server / Oracle / MS Access
CREATE TABLE TS
(
	id int NOT NULL PRIMARY KEY,
    name varchar(25),
    P_Id int NOT NULL FOREIGN KEY REFERENCES TES(P_Id)
)

​ UNIQUE 約束唯一標識數據庫表中的每條記錄,和主鍵不同,表中允許多個UNIQUE 約束出現,PRIMARY KEY 約束擁有自動定義的 UNIQUE 約束,這地方在處理數據的時候用到的時候沒有太多,就當瞭解一下。

​ 約束的創建

create table ts(
    id int NOT NULL,
    name varchar(25),
    UNIQUE (id) # UNIQUE 約束
);
或者
create table ts(
    id int NOT NULL UNIQUE,# UNIQUE 約束
    name varchar(25)
);

​ 約束的刪除

# MySQL
ALTER TABLE ts
DROP INDEX id

# SQL Server / Oracle / MS Access
ALTER TABLE Persons
DROP CONSTRAINT id

5.進階

1. 操作符
1.1 WHERE(無法與聚合函數一起使用)

​ 之前舉的一個查詢爲女生的同學的例子,傳統方法爲 for 循環,這樣耗時耗力,使用 where 我們可以很簡單的秒了

# 基本語法
SELECT column_name,column_name   # 需要查詢的列
FROM table_name
WHERE column_name operator value;   # 這裏爲一些條件語句,接下來會提及
1.2 IN

​ 當我們需要查詢某一鍵符合多個值的時候,這個便派上了用場

create table grade(
    name nchar(10),
    grade int
);
insert into grade values ('a', 100);
insert into grade values ('b', 100);
insert into grade values ('c', 90);
insert into grade values ('a', 100);
insert into grade values ('b', 95);
insert into grade values ('c', 93);

# 基本語法
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...);
# 查詢名字是a,b,c中間一人的數據
select * from grade
where name in ('a','b','c');  # 括號裏的元素要與鍵的數據類型相同
# 查詢成績是 90 93 100 之間的同學數據
select * from grade
where grade in (90, 93 ,100);
1.3 BETWEEN

​ 我們需要查詢某一鍵符合在某一範圍時,這個便派上了用場

# 基本語法
SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;

select * from grade
where grade between 95 and 100;
1.4 LIKE

​ LIKE 操作符用於在 WHERE 子句中搜索列中的指定模式,主要就是匹配模式的書寫,可能會涉及到正則表達式,下面給出 菜鳥課程 總結的通配符,對正則不熟悉的同學可參考我的另外一篇博文。

通配符 匹配對象
% 替代 0 個或多個字符
_ 替代一個字符
[charlist] 字符列中的任何單一字符
[^charlist] 或 [!charlist] 不在字符列中的任何單一字符

​ MySQL 中使用 REGEXPNOT REGEXP 運算符 (或 RLIKE 和 NOT RLIKE) 來操作正則表達式

# 查詢以 c或d或e開頭的同學名字的數據
select * from grade
where name REGEXP '^[cde]';

# 查詢以 c到e字母開頭的同學名字的數據
select * from grade
where name REGEXP '^[c-e]';

# 查詢 不以 c到e字母開頭的同學名字的數據
select * from grade
where name REGEXP '^[^c-e]';

# 查詢一個字母的同學名字的數據
select * from grade
where name like '_';
2. SELECT DISTINCT

​ 以上面 班級任課老師表 爲例,如果我們想要任課老師的教職工號,我們可以用 select 來只對 任課老師教職工號 進行選擇,但查詢的結果會有重複,C 的教職工號出現兩次,我們可以使用 SELECT DISTINCT 進行查詢而不會出現重複的情況。一個重要的特點就是每一條查詢結果都各不相同。

# 查詢參加考試的同學
select distinct name
from grade;

# 查詢考試分數的種類
select distinct grade
from grade;

# 查詢學生及其分數的種類
select distinct grade,name
from grade;
3. JOIN

​ join 用於將多個表聯繫在一起,大致可分爲四種join方法

join 類型 描述
INNER JOIN 如果表中有至少一個匹配,則返回行
LEFT JOIN 即使右表中沒有匹配,也從左表返回所有的行
RIGHT JOIN 即使左表中沒有匹配,也從右表返回所有的行
FULL JOIN 只要其中一個表中存在匹配,則返回行

create table TeaNo(
    name varchar(5) NOT NULL,
    Tno varchar(5) NOT NULL ,
    sex varchar(5) NOT NULL ,
    PRIMARY KEY (Tno)
);
create table Teach(
    Tno varchar(5) NOT NULL ,
    Teacher varchar(2) NOT NULL ,
    Class varchar(3) NOT NULL ,
    FOREIGN KEY (Tno) references TeaNo(Tno)

);

insert into TeaNo values ('C','03','男');
insert into TeaNo values ('B','02','男');
insert into TeaNo values ('A','01','女');
insert into TeaNo values ('D','04','女');

insert into Teach values ('03', 'C', '二班');
insert into Teach values ('01', 'A', '一班');
insert into Teach values ('03', 'C', '三班');
insert into Teach values ('03', 'B', '四班');

# inner join

select TeaNo.name,TeaNo.sex,Teach.Class
from TeaNo inner join Teach
on TeaNo.Tno = Teach.Tno;
# A,女,一班
# C,男,二班
# C,男,三班
# C,男,四班

# LEFT JOIN  B 和 D 老師都在右邊找不到對應的信息但仍返回左邊一行,空缺地方爲NULL

select TeaNo.name,TeaNo.sex,Teach.Class
from TeaNo left outer join Teach
on TeaNo.Tno = Teach.Tno;
# A,女,一班
# B,男,
# C,男,二班
# C,男,三班
# C,男,四班
# D,女,

# Right JOIN
select TeaNo.name,TeaNo.sex,Teach.Class
from TeaNo right outer join Teach
on TeaNo.Tno = Teach.Tno;
# C,男,二班
# A,女,一班
# C,男,三班
# C,男,四班

# FULL JOIN 似乎語法並不支持
4. 別名

​ 在進行查詢時,可以通過創建別名讓列名稱或者表名稱的可讀性更強。

# 列的別名
SELECT name AS TeacherName
FROM TeaNo;

# 表的別名 多用於多表查詢時
SELECT name
FROM TeaNo AS TeacherName;
5. SQL 函數

​ 在數據處理上,正是由於這些可以直接使用的函數,讓數據處理更加簡便,下列是菜鳥課程上總結的函數

函數名 作用
FORMAT() 格式化某個字段的顯示方式
LEN() 返回某個文本字段的長度
ROUND() 對某個數值字段進行指定小數位數的四捨五入
UCASE() 將某個字段轉換爲大寫
LCASE() 將某個字段轉換爲小寫
AVG() 返回平均值
COUNT() 返回行數
NOW() 返回當前的系統日期和時間
FIRST() 返回第一個記錄的值
LAST() 返回最後一個記錄的值
MAX() 返回最大值
MID() 從某個文本字段提取字符,MySql 中使用
SubString(字段,1,end) 從某個文本字段提取字符
MIN() 返回最小值
SUM() 返回總和
# FORMAT() 括號裏的元素都是必須的
SELECT FORMAT(column_name,format) FROM table_name; 

# 得到系統時間
select date_format(NOW(),'%Y-%m-%d') As data;
6. HAVING

​ 由於WHERE 關鍵字無法與聚合函數一起使用,因此引入Having,HAVING 子句可以讓我們篩選分組後的各組數據。

# 基本語法
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value;

# aggregate_function(column_name) 爲聚合函數,不能與 where 連用
7. Union 與 Union All

​ 二者用於合併兩個或多個 SELECT 語句的結果。

​ 注意事項:UNION 內部的每個 SELECT 語句必須擁有相同數量的列。列也必須擁有相似的數據類型。同時,每個 SELECT 語句中的列的順序必須相同。

​ 二者不同之處:Union 用於取並集去重,Union All 用於取並集不去重。

create table country1(
    Name varchar(10),
    Eng varchar(10)
);
create table country2(
    Name varchar(10),
    Eng varchar(10),
    amount int
);
insert into country1 values ('中國', 'CN');
insert into country1 values ('美國', 'USA');
insert into country1 values ('英國', 'UK');
insert into country1 values ('日本', 'Japan');
insert into country2 values ('德國','German',100);
insert into country2 values ('澳大利亞','Australia',100);
insert into country2 values ('俄羅斯','Russia',100);
insert into country2 values ('德國','German',100);
# 取並集 去重
select Name,Eng
from country1
UNION
select Name,Eng
from country2;
# 取並集不去重
select Name,Eng
from country1
UNION ALL
select Name,Eng
from country2;
8.日期問題

​ 日期處理問題是對數據進行提取,分類的重要環節,比如,在數學建模中,我們經常需要對一家公司的收入按月份或者年份進行提取,數據庫內置的函數就會有奇效。下列是菜鳥課程總結的一些函數。

函數名稱 函數用處
DATE(date) 提取 date 中的日期部分
DATE_ADD(date,INTERVAL expr type) 從日期加上指定的時間間隔。date 爲 合法的日期 ,expr 爲 指定的時間間隔
DATE_FORMAT() 用於以不同的格式顯示日期/時間數據。
DATE_SUB(date,INTERVAL expr type) 從日期減去指定的時間間隔。date 爲 合法的日期 ,expr 爲 指定的時間間隔
DATEDIFF(date1,date2) 返回兩個日期之間的天數date1 和 date2 參數是合法的日期或日期/時間表達式
EXTRACT() 用於返回日期/時間的單獨部分,如年,月,日
9. 視圖

​ 根據本人的理解,視圖就是將一個或者多個表之間關聯起來並作爲一個虛擬表返回,這個虛擬表是動態改變的,我們下次再次將多個表關聯起來時只需要操作視圖即可。

​ 在 SQL 中,視圖是基於 SQL 語句的結果集的可視化的表。視圖包含行和列,就像一個真實的表。視圖中的字段就是來自一個或多個數據庫中的真實的表中的字段。您可以向視圖添加 SQL 函數、WHERE 以及 JOIN 語句,也可以呈現數據,就像這些數據來自於某個單一的表一樣。

​ 視圖總是顯示最新的數據!每當用戶查詢視圖時,數據庫引擎通過使用視圖的 SQL 語句重建數據。

​ 視圖所查詢出來的數據只能進行查看,不能增刪改。

# 基本語法
CREATE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition
10. AND OR

​ 將多個條件結合進行篩選

​ and : 連接的條件都需要滿足

​ or : 連接的條件有一個滿足就可

11. GROUP BY 和 ORDER BY

​ ORDER BY 爲排序操作,根據指定的屬性來進行排序,可以指定升序以及降序

# 默認爲升序排列
select *
from grade
order by grade;

# 降序排列,先按成績,成績一樣再按分數
select *
from grade
order by grade,name desc;
12. EXISTS
SELECT column_name(s)
FROM table_name
WHERE EXISTS
(SELECT column_name FROM table_name WHERE condition);

# 首先執行 外部查詢 SELECT column_name(s) FROM table_name
# 將查詢到的每一條數據傳給內查詢,看內查詢能否查詢到結果,查詢不到返回Flase,反之爲True
# 內查詢返回爲 True 則保留外查詢這一條記錄
13.SELECT TOP

​ 用於規定要返回的記錄的數目,如果查詢返回的結果很多,輸出花費比較多,我們可以使用此語句來限定數目

# 適用於 SQL Server / MS Access
SELECT TOP number|percent column_name(s)
FROM table_name;
# 適用於 MySQL
SELECT column_name(s)
FROM table_name
LIMIT number;
# 適用於 Oracle
SELECT column_name(s)
FROM table_name
WHERE ROWNUM <= number;

select *
from Teach
limit 3;

6. 數據導出

# 導出數據
select * from table into outfile '路徑';

# 導入數據
load data local infile '路徑' into table 表名 fields terminated by ‘\t’

​ 在此之前,需要修改一下數據導出的默認路徑

使用 show variables like '%secure%'; 查看secure-file-priv設置,
  			2. secure_file_prive=null ––限制mysqld 不允許導入導出
     secure_file_priv=/path/ – --限制mysqld的導入導出只能發生在默認的/path/目錄下
     secure_file_priv=’’ – --不對mysqld 的導入 導出做限制
  			3. 在 mysql 的安轉目錄下找到 my.ini 文件,修改secure_file_prive 爲 '' 使其不對mysqld 的導入 導出做限制
  			4. 打開計算機管理>>服務與應用程序>>服務>>mysql(版本不同名字可能不同)>>右鍵重新啓動>>完成重啓
  			5. 重複 1 步驟,看看修改是否成功,若沒有成功可以試試重啓電腦。
  			6. 之後再進行導入導出操作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章