一文带你用 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. 之后再进行导入导出操作

你可能感兴趣的:(Mysql,数学建模,mysql,大数据,数据库)