SQL学习指南第一篇
SQL语言的分类
用于创建数据库对象(表,索引,约束等)的语句统称为 SQL 模式语句,而用于创建,操纵和检索保存在数据库中的数据的语句称为 SQL 数据语句。
SQL语言中的术语和定义
术语 | 定义 |
---|---|
实体 | 数据库用户所关注的对象,如顾客,部门,地理位置等 |
列 | 存储在表中的独立数据片段 |
行 | 所有列的一个集合,完整地描述了一个实体或实体上的某个行为,也称之为记录 |
表 | 行的集合,既可以保存在内存中(未持久化),也可以保存在存储设备中(已持久化) |
结果集 | 未持久化表的另一个名字,一般为SQL查询的结果 |
主键 | 用于唯一标识表中每个行的一个或多个列 |
外键 | 一个或多个用于识别其他表中某一行的列 |
SQL — 非过程化语句
过程化语言对所期望的结果和产生这些结果的执行机制或过程都进行了定义。非过程化语言同样定义了期望结果,但将产生结果的过程留给外部代理来定义。使用 SQL 意味着必须放弃对过程的控制,因为 SQL 语句只定义必要的输入和输出,而执行语句的方式则交由数据库引擎的一个组件,即优化器处理。
MySQL执行外部sql脚本文件:
打开CMD,登录MySQL,关联数据库,将文件拖入命令行界面会出现路径,在路径前面加上source,加上空格,结尾不要;
MySQL数据类型
这里只介绍简单数据类型:字符型,数值型和日期型。
字符型数据
字符型数据可以使用定长或变长的字符串来实现,其不同点在于固定长度的字符串使用空格向右填充,以保证占用同样的字节数;变长字符串不需要向右填充,并且所有字节数可变。当定义一个字符列时,必须指定该列所能存放字符串的最大长度。char 列可以设置的最大长度为255个字节,而varchar列最多可以存储65535个字节。
字符集
SHOW CHARACTER SET;
命令可以查看服务器所支持的字符集;创建数据库和表时可以指定字符集。
文本数据
如果需要存储的数据超过64KB(varchar列所能容许的上限),就需要使用文本类型。MySQL文本类型有以下这四个:tinytext,text,mediumtext,longtext。
数值型数据
MySQL的整数类型有以下这四个:tinyint(-128127),smallint(-3276832767),mediumint(-83886088388607),int(-21474836482147483647),bigint。MySQL的浮点类型有以下这两个:float(p, s),double(p, s)。当使用浮点类型时,可以指定其精度和有效位,当然这不是必需的。如果数据超过了该列所定义的有效位,那么该数据将会被四舍五入。数值型数据类型还可以加上 unsigned 关键字,指明该列存储的数据大于等于0。
时间数据
MySQL的时间类型有以下这五个:date,datetime,timestamp,year,time。timestamp保存的信息与datetime类型一样(包括年,月,日,时,分,秒),但 MySQL 服务器可以在向表中增加或修改数据行时自动为timestamp列产生当前的日期/时间。
数据生成,转换和操作
本章继续讨论3种常用的数据类型(字符型,数值型和时间型)
使用字符串数据
MySQL中有以下字符数据类型:
- CHAR 固定长度,不足部分用空格填充
- VARCHAR 变长字符串
- TEXT 容纳大长度的变长字符串
生成字符串
向表中插入的字符串数据长度超过字符列的最大长度时,服务器会抛出异常,而在早先的服务器版本中,默认方式是截断字符串并发出一个警告。如果希望数据库引擎采取后一种方式,可以将之修改为ANSI模式。
SET sql_mode = 'ansi'; -- 改变模式
SELECT @@session.sql_mode; --查看数据库的当前模式
如果字符串中包含单引号,则需要在单引号前面加入转义符进行转义。MySQL既支持单引号前面加个单引号进行转义也支持使用反斜杠作为单引号的转义符。如果需要为获取的字符串增加转义符,可以使用MySQL自带的内建函数quote(),它用单引号将整个字符串包含起来,并为字符串本身的单引号/撇号增加转义符。例如:SELECT quote(text_fld) FROM string_tbl;
操作字符串
length()函数返回字符串的字符数;position()函数查找字符串中子字符串的位置(第一个字符位置号为1);concat()函数连接若干字符串;insert()函数插入或替换原始字符串中的字符,它接受4个参数:原始字符串,字符串操作的开始位置,需要替换的字符数以及替换字符串;substring()函数用于从指定的位置提取指定数目的字符;rtrim()函数,ltrim()函数,trim()函数用来消除空格。
SELECT LENGTH(列名) FROM tableName;
SELECT POSITION(str IN 列名) FROM tableName;
SELECT CONCAT(fname, ' ', lname) name FROM employee;
SELECT INSERT('goodbye world', 9, 0, 'cruel ') string; --如果第三个参数的值为0,那么替换字符串将会被插入其中,并且剩余的字符将会向右排放
SELECT SUBSTRING('goodbye cruel world', 9, 5); --三个参数:指定字符串,指定位置,指定数目的字符
使用数值数据
执行算术函数
sin(x),cos(x),sqrt(x),mod(x, y),pow(x, y)等等
控制数字精度
ceil()和floor()函数用于向上或向下截取整型数字;round()对浮点数的小数位进行四舍五入;truncate()只是简单地去掉不需要的小数位,不进行四舍五入且第二个参数不可省。
SELECT CEIL(72.445), FLOOR(72.445), ROUND(72.0909, 1), TRUNCATE(72.0909, 1);
使用时间数据
处理时区
世界各地的人们都将太阳直射本地的时间作为正午,因此没有办法强迫所有人使用统一的时钟,因此,世界被划分为24个时区。大多数数据库服务器根据当前所在地区设置默认的时区,并提供工具以便在需要的时候进行修改。
MySQL提供两个不同的时区设置:全局时区和会话时区,后者可能对于每个登录用户都是不同的。
SELECT @@global.time_zone, @@session.time_zone;
结果值为system,这表明数据库根据数据库所在地使用相应的时区设置。如果想改变当前会话的时区设置,可以使用 set 命令。
生成时间数据
执行返回date,datetime或time型数据的内建函数;构建可以被服务器识别的代表日期的字符串。对于后者,我们必须首先理解格式化日期的各种组件。
表:必需的日期部件
类型 | 默认格式 |
---|---|
Date | YYYY-MM-DD |
Datetime | YYYY-MM-DD HH:MI:SS |
Timestamp | YYYY-MM-DD HH:MI:SS |
Time | HHH:MI:SS |
如果需要产生当前日期/时间,可以直接利用内建函数获取系统时钟并返回当前的日期或时间字符串:
SELECT CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP();
操作时间数据
- year()函数从日期中提取年份,例如:
SELECT order_num FROM Orders WHERE YEAR(order_date) = 2012;
- datediff()函数返回两个日期之间的天数,例如:
SELECT DATEDIFF('2019-06-23', '2019-03-16');
- dayname()函数可以确定某一日期是星期几,例如:
SELECT DAYNAME('2019-03-16');
- extract()函数用于提取日期值中的信息,例如:
SELECT EXTRACT(YEAR FROM '2008-09-18 22:19:05');
- date_add()函数可以为指定日期增加任意一段时间间隔(如天,月,年)并产生一个新的日期,例如:
SELECT DATE_ADD(CURRENT_DATE(), INTERVAL 5 DAY);
(其中第二个参数包含了 3 个元素:interval 关键字,所需要增加的数量以及时间间隔的类型。) - last_day()函数可以求得当前月份的最后一天并返回一个新的date型日期,例如:
SELECT LAST_DAY('2019-06-09');
下面的表显示了一些常用的时间间隔类型:
间隔名称 | 描述 |
---|---|
Second | 秒数 |
Minute | 分钟数 |
Hour | 小时数 |
Day | 天数 |
Month | 月份 |
Year | 年份 |
Minute_second | 分钟数和秒数,中间用 " :" 隔开 |
Hour_second | 小时数,分钟数和秒数,中间用 " :" 隔开 |
Year_month | 年份和月份,中间用 "-" 隔开 |
例如:你得知ID为9999的交易实际发生的时间比transaction表中当前记录的时间要晚3小时27分钟11秒,那么可以使用下面的方法进行修正:
UPDATE transaction SET txn_date = DATE_ADD(txn_date, INTERVAL '3:27:11' HOUR_SECOND) WHERE txn_id = 9999;
创建,修改和删除表
表是由行(Row)和列(Column)组成的。表中的一行称为一个元祖,相当于一条记录。表中的每列称为一个字段,每列的标题称为字段名。每个表中通常都有一个主关键字,用于唯一地确定一条记录。
创建表
例如:
CREATE TABLE users(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
phone VARCHAR(11) NOT NULL,
username VARCHAR(30) NOT NULL,
password VARCHAR(100) NOT NULL,
avatar VARCHAR(30) DEFAULT 'default.jpg',
intro VARCHAR(200)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4;
创建临时表
当我们需要查询一个大量数据的小的子集时,不是对整个表运行查询,而是让MySQL先找出所需的少数记录,将这些记录保存在临时表中,然后在这个临时表中进行查询。
例如:
create temporary table emp_tmp as
select emp_id, fname, lname from employee;
修改表
查看列的信息
DESC 表名;
查看表的所有信息
SHOW CREATE TABLE table_name;
增加新列
ALTER TABLE table_name ADD COLUMN column_name data_type;
删除列
ALTER TABLE table_name DROP COLUMN column_name;
修改列
ALTER TABLE table_name MODIFY column_name data_type;
例如:ALTER TABLE person MODIFY person_id INT UNSIGNED AUTO_INCREMENT;
或者
ALTER TABLE table_name CHANGE old_column_name new_column_name data_type;
插入,更新和删除数据
插入数据
插入有几种方式:
- 插入完整的行
- 插入行的一部分
- 插入某些查询的结果(INSERT SELECT)
例如:
INSERT INTO individual (cust_id, fname, lname, birth_date)
SELECT cust_id, 'James', 'Hadley', '1972-04-22' FROM customer WHERE fed_id = '111-11-1111';
insert into account (account_id, product_cd, cust_id, open_date, last_activity_date, status, open_branch_id, open_emp_id, avail_balance, pending_balance)
select null, a.prod_cd, c.cust_id, a.open_date, a.last_date, 'ACTIVE', e.branch_id, e.emp_id, a.avail, a.pend
from customer c cross join
(select b.branch_id, e.emp_id
from branch b inner join employee e on e.assigned_branch_id = b.branch_id
where b.city = 'Woburn' limit 1) e
cross join
(select 'CHK' prod_cd, '2000-01-15' open_date, '2005-01-04' last_date,
1057.75 avail, 1057.75 pend union all
select 'SAV' prod_cd, '2000-01-15' open_date, '2004-12-19' last_date,
500.00 avail, 500.00 pend union all
select 'CD' prod_cd, '2004-06-30' open_date, '2004-06-30' last_date,
3000.00 avail, 3000.00 pend) a
where c.fed_id = '111-11-1111';
注意:省略列
如果表的定义允许,则可以在 INSERT 操作中省略某些列。省略的列必须满足以下某个条件:
- 该列定义为允许 NULL 值(无值或空值),注:创建表时,如果不指定 NOT NULL,就认为指定的是 NULL。
- 在表定义中给出默认值。这表示如果不给出值,将使用默认值。
如果表中不允许有 NULL 值或者默认值,这时却省略了表中的值,DBMS 就会产生错误消息,相应的行不能成功插入。
从一个表复制到另一个表
有一种数据插入不使用 INSERT 语句。要将一个表的内容复制到一个全新的表(运行中创建的表),可以使用 SELECT INTO 语句。在 MySQL 里的语法是:
CREATE TABLE CustCopy AS SELECT * FROM Customers;
这条 SELECT 语句创建一个名为 CustCopy 的新表,并把 Customers 表的整个内容复制到新表中。因为这里使用的是 SELECT *
,所以将在 CustCopy 表中创建(并填充)与Customers 表的每一列相同的列。要想只复制部分的列,可以明确给出列名,而不是使用*通配符。SELECT INTO 是试验新 SQL 语句前进行表复制的很好工具。先进行复制,可在复制的数据上测试 SQL 代码,而不会影响实际的数据。
更新数据
基本的 UPDATE 语句由三部分组成,分别是:
- 要更新的表
- 列名和它们的新值
- 确定要更新哪些行的过滤条件
UPDATE Customers
SET cust_contact = 'Sam Roberts', cust_email = 'sam@toyland.com'
WHERE cust_id = '1000000006';
删除数据
DELETE FROM Customers
WHERE cust_id = '1000000006';
约束
检查约束
限制一列的可用值范围,使用 CHECK 关键字,用法如下:
1:在创建表时创建检查约束
CHECK (检查约束)
2:通过修改表添加检查约束
ALTER TABLE table_name ADD CONSTRAINT 检查约束名 CHECK (检查约束);
主键约束与外键约束
这两个约束是平时比较常见的。
1:在创建表时创建主键约束和外键约束,例如:
CREATE TABLE favorite_food(
person_id INT UNSIGNED,
food VARCHAR(20),
CONSTRAINT pk_favorite_food PRIMARY KEY (person_id, food),
CONSTRAINT pk_fav_food_person_id FOREIGN KEY (person_id) REFERENCES person (person_id)
);
2:通过修改表创建主键约束和外键约束
ALTER TABLE table_name ADD CONSTRAINT 主键约束名 PRIMARY KEY (主键字段);
ALTER TABLE table_name ADD CONSTRAINT 外键约束名 FOREIGN KEY (外键字段) REFERENCES 关联表名 (关联字段);
外键约束只能在使用InnoDB存储引擎创建表时才起作用