《深刻浅出SQL》问答录

在这里插入图片描述

本系列出自《深刻浅出SQL》,全文以问答形式展开,是个人我的学习笔记。web

文章目录

若是我只有一张白表,我为何还要建立数据库?

A:SQL语言要求全部的表都放在数据库中,这固然有它的理由。SQL能控制多位用户同时访问表的行为,可以授予或撤销对整个数据库的访问权,这有时比控制每张表的权限要简单的多。sql

我发现CREATE DATABASE 命令的字母全是大写,必定要这样吗?

A:有些系统确实要求某些关键字采用大写形式,但SQL自己不区分大小写。也就是说,命令不大小写也能够,但命令大小写是良好的SQL编程惯例。
大写让咱们很容易分辨命令与数据库名称。数据库

给数据库、表和列命名时有什么注意事项吗?

A:建立具备描述性的名称一般有不错的效果。有时候要多用几个单词来命名。全部名称都不能包含空格,因此使用下划线可以让你建立更具描述性的名称。
命名时最好避免首字母大写,由于SQL不区分大小写,很可能会搞错数据库。编程

为何不能直接把BLOB当成全部文本值的类型?

A:由于这样很浪费空间。VARCHAR或CHAR只会占用特定空间,不会多于256个字符。但BLOB须要很大的存储空间。
另外,有些重要的字符串运算没法操做BLOB类型的数据,只能用于VARCHAR或CHAR。浏览器

NULL是什么都没有的意思吗?

A:固然不是!! 它历来就不等于0。并且它也不等于另外一个NULL,事实上,两个NULL根本不能放在一块儿比较。值能够是NULL,可是它不会等于NULL,由于NULL表明未定义的值!cookie

花絮

  1. DEC(6,2):六位数,其中小数点后两位数。
  2. DATATIME(时间和日期):10:30 a.m. 9/29/2020
  3. 若是想查看表的数据结构,可使DESC语句
  4. DRAP TABLE 语句能够用于丢弃表,谨慎使用!
  5. 为表插入数据时,可使用任何一种INSERT语句。
  6. NULL是未定义的值。它不等于0,也不是空值。值能够是NULL,但绝非等于NULL。
  7. 没有在INSERT语句中被赋值的列默认为NULL。
  8. 能够把列修改成不使用NULL,这须要在建立表时使用关键字NOT NULL。
  9. 建立表时使用DEFAULT,可于往后输入缺少部分数据的记录时自动的填入默认值。

我试着从网络上复制并粘贴查询,但在使用时却一直出现错误信息,我作错什么了吗?

A:从web浏览器剪切过来的查询有时包含了外观像空格,但在SQL里有其余含义的隐形字符。你能够把查询粘贴到文本编辑器中,如此一来,就能够仔细寻找并移除这些小麻烦。网络

因此我应该把查询粘贴到Microsoft Word之类的软件中吗?

A:建议使用norepad(PC)或TextEdit(Mac)的纯文本编辑模式。数据结构

关于单引号的两种转义方法,哪种比较好呢?

A:其实没有优劣之分,可是斜杠对咱们肉眼有利。编程语言

如果NOT 搭配 AND/OR,该如何处置?

A:若是想在AND或OR子句中使用NOT,请直接将它放在关键字后面,以下:
SELECT * FROM asd WHERE NOT main = ‘aaa’ AND NOT mian = ‘bbb’;编辑器

花絮

  1. 在条件语句中,要查找空元素,应该使用 IS NULL
  2. 模糊查询(like)与它的通配符(%、_):匹配任意数量、单个数量
  3. 取定一个范围的数据:BETWEEN…AND…
  4. 枚举选定:in :select XXX from XXX where XXX IN(XXX、XXX、XXX),select XXX from XXX where XXX NOT IN(XXX、XXX、XXX).

为何不能假设最后一条记录就是最新的记录?

A:由于表中的记录排序方式没有必定的规则,并且咱们很快又要调整查询结果的记录,因此实在没法保证表的最后一条记录是最后插入的记录。除非咱们记住哪份数据先进来。

数据会改变,因此知道如何改变数据才会如此重要。

A:但表设计的越好,总体所需的更新操做就会越少。良好的表设计能让咱们从专心于表的内容中解放出来。

查询表时是否应该避免使用LIKE?LIKE有问题吗?

A:LIKE没有问题,但可能很难运用到你的查询中,并且你会冒着找出你不须要的一大堆数据的风险。若是你的列包含复杂信息的话,LIKE搜索精确数据的能力还不够。

为什简短的查询优于较长的查询?

A:查询越简短越好。随着数据的增加,还有对新表的添加,你的查询就会变得愈来愈复杂。若是如今就练习设计最简单的查询,之后你会感谢如今的及早训练。

简述建立表的思路

A:一、挑出事物,挑出你但愿表描述的某样事物。
二、列一份关于那样事物的信息列表,这些信息都是使用表时的必要信息。
三、使用信息列表,把关于那样事物的综合信息拆分红小块信息,以便用于组织表。

原子不是很小吗?我是否是应该把数据分割成很是很是小的片断?

A:不是哦,让数据具备原子性,表示把数据分割成建立有效率的表所需的最小片断。
别把数据切割的超出必要。若是不须要增长额外的列,就别由于能够增长而增长。

原子性对我有什么帮助?

A:原子性有助于确保表内容的准确性。
原子性也可使查询更加有效率。由于查询会因原子性而更容易设计,并且所需时间也更短,所以在面对大量数据时有加分效果。

主键规则说说看?

A:一、主键用于独一无二地识别出每条记录。
二、主键不能够为NULL。
三、插入新纪录时必须指定主键值。
四、主键必须简洁。
五、主键不能够被修改。

花絮

  1. 谨慎使用DELETE和UPDATE,使用SELECT确认本身加入了很是精确的WHERE语句,能够只选出你真正想要删除/修改的行。
  2. 使用UPDATE,你能够改变单一列或全部列的值。
  3. 在SET子句中加入更多的column = value组,其间以逗号分隔。
  4. UPDATE可用于更新单一的行或多行,一切交给WHERE子句决定。
  5. 自动递增关键字:AUTO_INCREMENT

若是我想改变列的顺序呢?像ALTER TABLE MODIFY COLUMN proj_desc AFTER con_name;这样作能够吗?

建立表后你就没法真正的改变列的顺序了。最多只能在指定位置添加新列,而后删除旧列,可是这样会失去旧列中的全部数据。

若是我已经建立了主键,而后又意外的想改用另外一列呢?能够只移除主键的设置而不改变其中的数据吗?

A:能够,并且很简单。ALTER TABLE your_table DROP PRIMARY KEY,ADD PRIMARY KEY(XXX);

AUTO_INCREMENT又该如何处理/

A:你能够把它添加到没有自动递增功能的列中,以下所示:ALTER TABLE your_table CHANGE yoour_id your_id INT(11) NOT NIULL AUTO_INCREMENT;
并且能够这样就将它删除:ALTER TABLE your_table CHANGE your_id your_id INT(11) NOT NULL;
有一点要记住:每一个表中只有一列能够加上AUTO_INCREMENT,该列必须为整形并且不能包含NULL。

花絮

ALTER使用示例

ALTER TABLE my_contacts
ADD COLUMN contact_id INT NOT NULL AUTO_INCREMENT FIRST,
ADD PRIMARY KEY(contact_id);
ALTER TABLE my_contacts 
ADD COLUMN phone VARCHAR(10)
AFTER list_name;
CHANGE --可同时改变现有列的名称和数据类型
MODIFY --修改现有列的数据类型或数据
ADD    --在当前表中添加一列,可自选类型
DROP   --从当前表中删除某列
ALTER TABLE project_list
CHANGE COLUMN number proj_id INT NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY(proj_id);
--将原名为“name”的列的名称和类型修改
--若是把数据改为另外一种类型,你可能会丢失数据
ALTER TABLE project_list
CHANGE COLUMN descriptionofproj proj_desc VARCHAR(10),
CHANGE COLUMN contractoronjob con_name VARCHAR(30),
ALTER TABLE project_list
MODIFY COLUMN proj_desc VARCHAR(120);
ALTER TABLE project_list
DROP COLUMN start_date;

一些便利的字符串函数

SELECT RIGHT(lie,2) FROM my_contacts;	--从lie列中读取两个字符
SELECT SUBSTRING_INDEX(lie,',',1) FROM my_contacts;
--截取部分字符串,第三个参数就是寻找第一个逗号,用于截取第一个逗号以前的全部字符。
SELECT UPPER('usa');	--把整整组字符串改大写
SELECT LOWER('USA');	--改小写
SELECT LTRIM(' dogfood ');	--清除左侧空格
SELECT RTRIM(' catfood ');
SELECT LENGTH('San Antonio,TX'); --返回字符串中的字符数量

要用到ELSE吗?

A:看你咯,无所谓。

若是没有ELSE并且列也不符合任何一个WHEN条件,会发生什么事?

在你想更新的列里面不会发生任何改变。

若是我只想对部分列套用CASE表达式,应该怎么作呢?

A:能够加上WHERE,能够在END后加上WHERE子句。这样,CASE就只会套用在符合WHERE子句的列上。

CASE表达式能够搭配UPDATE之外的语句吗?

A:why not?

讲到MIN,若是查询中的列有NULL,这会有上面影响吗?

A:好问题。NULL其实不会有影响,由于NULL表明此处无值,而不是此值为0.

花絮

CASE语句

看图:
在这里插入图片描述
在这里插入图片描述

如今怎么办?是像这样吗?

在这里插入图片描述

这样要执行n次啊。。。

那有没有更好的办法,其实在主语言中,这不过就是个分支语句的事情嘛,奈何SQL语言我不熟啊。。。

没事,一直以来不懂,从今之后懂了:

UPDATE my_table
SET new_column =
CASE
	WHEN column1 = somevalue1
		THEN newvalue1
	WHEN column2 = somevalue2
		THEN newvalue2
	ELSE newvalue3
END;

在这里插入图片描述

ORDER BY排序

一、升序排序:ASC | 降序排序:DESC
二、SQL排序规则

在这里插入图片描述

多列排序:

越靠前的列权重越高,拥有对后面列的一票否决权。

GROUP BY 分组

SELECT first_name,SUM(sales)
FROM cookie_sales
GROUP BY first_name
ORDER BY SUM(sales) DESC
;
SELECT first_name,AVG(sales)
FROM cookie_sales
GROUP BY first_name
ORDER BY AVG(sales) DESC
;
SELECT first_name,MAX(sales)
FROM cookie_sales
GROUP BY first_name
;
SELECT first_name,MIN(sales)
FROM cookie_sales
GROUP BY first_name
;

COUNT,计数

SELECT COUNT(sale_date)
FROM cookie_sales
;

DISTINCT,取独

SELECT DISTINCT sale_date
FROM cookie_sales
ORDER BY sale_date
;
SELECT COUNT(DISTINCT sale_date)
FROM cookie_sales
;

LIMIT:限制查询数量

SELECT first_name,SUN(sales)
FROM cookie_sales
GROUP BY first_name
ORDER BY SUN(sales) DESC
LIMIT 2 OFFSET 4	--跳过两条,查询两条记录
--也能够这样写:LIMIT 4,2
;

若是外键是NULL,它右什么做用吗?有办法肯定外键已经链接到父键了吗?

A:外键为NULL,表示在父表中没有相符的主键。但咱们能够确认外键包含有意义、已经存储在父表中的值,请经过约束实现。

不能单纯的使用另外一张表的键,称之为外键,而不加上约束吗?

A:其实能够,但建立成外键约束后,就只能插入已经存在于父表中的值,有助于增强两张表间的链接。

增强链接?是什么意思?

A:外键约束能确保引用完整性(换句话说,若是表中的某行有外键,约束能确保该行经过外键与另外一张表中的某一行一一对应)。若是咱们试着删除主键表中的行或者是改变主键值,而这个主键是其余表的外键约束时,你就会收到错误警告。

因此上面说的那种,我就不能删除了是吗?

A:仍是能够的,先移除外键行便可。

遇到多对多关系的时候,必定要用中间件吗?

A:否则呢?

花絮

数据库解析图

在这里插入图片描述
建立数据库的视觉解析图,在设计查询时有助于理解数据相连的方式,但模式也能以文字形式表达,看我的。

外键

在这里插入图片描述
在这里插入图片描述

外键约束

建立一张表并加上可做为外键的列虽然很简单,但除非你利用CREATE或ALTER语句来指定外键,不然都不算是真的外键。建立在结构内的外键被称为约束。

插入外键列的值必须已经存在与父表的来源中,这是引用完整性。

建立外键做为表的约束提供了明确的优点,若是违反了规则,约束会阻止咱们破坏表。

外键不必定要是父表的主键,可是要具备惟一性。
在这里插入图片描述

设计数据库模式

数据模式:一对一

在模式图中,一对一关系的链接线是单纯的实线,表示链接一件事物与另外一件事物。

在这里插入图片描述

使用一对一的时机

事实上,不多。

  1. 抽出数据或许能让你写出更快速的查询。
  2. 若是有列包含还不知道的值,能够单独存储这一列,以避免主表中出现NULL。
  3. 咱们可能但愿某些数据不要太常被访问,隔离这些数据,便可管制访问次数。一员工表为例,他们的薪资信息最好另存一张表。
  4. 若是有一大块数据,例如BLOB类型,这段数据或许另存为另外一张表会更好。
数据模式:一对多

A表的某一条记录能够对应到B表的多条记录,但B表中的一条记录只能对应A表中的某一条记录。
在这里插入图片描述
链接线应该带有黑色箭头来表示一对多的链接关系。

在这里插入图片描述

数据模式:多对多

在这里插入图片描述
司空见惯了,中介者模式(调停者模式)该上场了。

Junction table(链接表)

在这里插入图片描述

范式(NF)

第一范式(1NF)
  1. 数据列只包含具备院子性的值
  2. 没有重复的数据组
组合键

组合键就是有多个数据列构成的主键。

第二范式(2NF)
  1. 符合1NF
  2. 没有部分函数依赖性
函数依赖性

当某列的数据必须随着另外一列的数据改变而改变时,表示第一列函数依赖与第二列。

部分函数依赖:非主键的列依赖与组合键的某个部分(但不是彻底依赖与组合主键)。

传递函数依赖:若是改变任何非键列可能形成其余列的改变,即为传递依赖。

第三范式(3NF)
  1. 符合2NF
  2. 没有传递函数依赖性

我为何须要交叉联接?

A:知道交叉联接的存在,有助于咱们找出修正联接的正确方式。还有,交叉联接有时可用于RDBMS软件及其配置的运行速度。运行交叉联接所需的时间能够轻易的检测与比较出速度慢的查询。

内联接和交叉联接有什么区别吗?

A:交叉联接属于内联接的一种。内联接就是经过查询中的条件移除了某些结果的交叉联接。

能够联接多于两张表吗?

A:能够,后续章节再说,有点饿了。

ORDER BY 这些东西也能与联接放到一块儿吗?

A:是的。

外联接呢?

A:莫急。

花絮

字符串切割函数

在这里插入图片描述

在这里插入图片描述

同时(几乎同时)CREATE、SELECT、INSERT

CREATE TABLE profession(
	id INT(11) NOT NULL AUTP+INCREMENT PRIMARY KEY,
	profession varchar(20)
);
INSERT INTO profession (profession)
	SELECT profession FROM my_contacts
	GROUP BY profession
	ORDER BY profession;
CREATE TABLE profession AS
	SELECT profession FROM my_contacts
	GROUP BY profession
	ORDER BY profession;
ALTER TABLE profession
ADD COLUMN id INT NOT NULL AUTO_INCREMENT FIRST,
ADD PRIMARY KEY(id);
CREATE TABLE profession(
	id INT(11) NOT NULL AUTP+INCREMENT PRIMARY KEY,
	profession varchar(20)
) AS
	SELECT profession FROM my_contacts
	GROUP BY profession
	ORDER BY profession;

关键字AS

看上面语句,AS能把SELECT的查询结果填入表中。

短短一个查询语句,就出现了五次“profession”,这五次profession效果各有不一样,咱们容易弄晕,可是SQL可以很轻易的分辨。
为了能让咱们容易分辨,SQL推出了假名功能。

建立别名真的很简单,在查询软件中首次使用原始列名的地方后接一个AS并设定要采用的别名,告诉软件如今开始要以另外一个名称引用my_contacs表的profession列,这样可让查询更容易被咱们理解。

在这里插入图片描述
在这里插入图片描述

表的别名,谁会须要?

你会须要!
接下来要开始对表进行联结了,嘿嘿,睁大眼睛吧。

建立表的别名的方式和建立列的别名的方式几乎同样。在查询中首次出现表名的地方后接AS并设定别名。
固然,你甚至能够连AS也省了。

联接

交叉联接(笛卡尔积)

假设你有一个存储男孩姓名的表以及一个记录男孩们都有哪些玩具的表,如今咱们要试着找出每一个男孩拥有的玩具。

在这里插入图片描述

SELECT t.toy,b.boy
From toys t
	CROSS JOIN
	boys AS b
;

CROSS JOIN返回两张表的每一行相乘的结果。
在这里插入图片描述

内联接

INNER JOIN利用条件判断中的比较运算符结合两张表的记录。只有联接记录符合记录条件时才会返回列。

SELECT somecolumns
FROM table1
	INNER JOIN
	table2
ON somecondition;	--条件式里课采用任何一个比较运算符,也能够改用WHERE

示例:
在这里插入图片描述

SELECT mc.last_name,mc.first_name,p.profession
FROM my_contacts AS mc
	INNER JOIN
	profession AS p
ON mc.prof_id = p.prof_id;

在这里插入图片描述

天然联接

属于内联接的一种。
天然联接只有在联接的列在两张表中的名称相同时才会用。
在这里插入图片描述

SELECT boys.boy,toys.toy
FROM boys
	NATURAL JOIN
	toys;

在这里插入图片描述

子查询解析

在单一查询不够用的时候,请使用子查询。

子查询只不过是查询里的查询。

SELECT some_column,anther_column
FROM table
WHERE column = (SELECT column FROM table);

由于查询里使用了 = 运算符,因此子查询里只会返回单一值,特定行和列的交叉点,这一个值将是WHERE子句中比对数据列的条件。

SELECT zip_code 
FROM zip_code WHERE city = 
	(SELECT zip_code 
	From zip_code
	WHERE city = 'Memphis' AND state  ='TN' 
	)
;

在这里插入图片描述

非关联子查询

若是子查询能够独立运行且不会引用外层查询的任何结果,即称为外层查询。
上面都是

有时候最好建立测试数据库来尝试各类查询方式,比较查询运行时间。
联接比子查询更有效率。

关联子查询

关联子查询是内层查询的解析须要依赖于外层查询的结果。

关联子查询的常见用法是找出全部外层查询结果里不存在于关联表里的数据。

SELECT mc.first_name firstname,mc.last_name lastname,mc.email email
FROM my_contacts mc
WHERE NOT EXISTS(
SELECT * FROM job_cerrent jc
WHERE mc.contact_id = jc.contact_id
) ;

内层查询究竟能够返回什么?外层查询呢?

A:大多数状况下,内层查询只能返回单一值,也就是一列里的一行。然后,外层查询才能利用这个值与列中其余值进行比较。
通常而言,子查询必须返回一个值,使用IN是例外状况。

因此说,子查询能够放在子查询里吗?

A:of couse.

听说使用子查询能解决的事情,用联接也能够?是这样吗?

A:否则呢?


左外联接

LEFT OUTER JOIN 会匹配左表中的每一行及右表中符合条件的行。
当左表与右表具备一对多关系时,左外联接特别有用。

理解外联接的最大秘密在于知道表在左边仍是右边,在LEFT OUTER JOIN中,出如今FROM后,联接前的表称为左表,而出如今联接后的表称为右表。

SELECT g.girl,t.toy
FROM girls g	--g是左表
LEFT OUTER JOIN toys t	--t是右表
ON g.toy_id = t.toy_id;

内外联接有什么差异?外联接必定会提供数据行,不管该行可否在另外一个表中找出相匹配的行。
左外联接的结果为NULL表示右表没有找到与左表相符的记录。
在这里插入图片描述

具体流程概览(图有点小瑕疵):
在这里插入图片描述

右外联接

有外联接与左外联接同样,除了它是用右表与左表比对。

自联接

同一个表能够同时做为外联接的左右表。虽然听起来很奇怪,不过却很好用。

来一题看看;
在这里插入图片描述

SELECT c1.name,c2.name AS boss
FROM clown_info1 c1
INNER JOIN clown_info2 c2
ON c1.bossid = c2.id
;

自联接可以把一张表当成两张彻底相同的表来进行查询。

UNION

还有一种取得多张表的查询结果的方式:UNION联合。

UNION根据咱们在SELECT中指定的列,把两张表或更多张表的查询结果合并至一个表中。

SELECT title FROM job_current
UNION
SELECT title FROM job_desired
UNION
SELECT title FROM job_listings;
UNION的使用限制

在这里插入图片描述

示例
SELECT title FROM job_current
UNION
SELECT title FROM job_desired
UNION
SELECT title FROM job_listings
ORDER BY title;

结果集:
在这里插入图片描述

SELECT title FROM job_current
UNION ALL
SELECT title FROM job_desired
UNION ALL
SELECT title FROM job_listings
ORDER BY title;

结果集:
在这里插入图片描述

联合规则说:选取的列必须能够互相转换

联接VS子查询

在这里插入图片描述
在这里插入图片描述

有使用左外链接取代右外联接的理由吗?

A:通常来讲,固定使用一种联接的习惯会让事情更简单,这样不容易搞混。

检查约束

CREATE TABLE piggy_bank(
	id INT NOT NULL PRIMARY KEY,
	coin CHAR(1) CHECK (coin IN ('P','N','D','Q'))
);

CHECK(检查)用于限定容许插入某个列的值。它与WHERE子句都使用相同的条件表达式。
若是插入的值没法经过CHECk条件,则出现错误信息。

ALTER TABLE my_contacts
ADD CONSTRAINT CHECk gender IN ('M','F');

视图

建立视图

CREATE VIEW web_designers AS
SELECT mc.first_name,mc.last_name.mc.phone,mc.email
FROM my_contacts mc
NATURAL JOIN job_desired jd
WHERE jd.title = 'Web Designer';

查看视图

就像普通表那样。

SELECT * FROM web_designers;

视图的实际行动

SELECT* FROM(
SELECT mc.first_name,mc.last_name,mc.phone,mc.email
FROM my_contacts mc
NATURAL JOIN job_desired jd
WHERE jd.title = 'Web Designer' AS web_designers;
)

最后为何要用个AS呢?由于当SELECT语句的结果是一个虚表时,若没有别名,SQL就没法取得其中的表。

为何视图对数据库有好处?

  1. 若是建立了视图,就不须要重复建立复杂的联接与子查询。视图隐藏了子查询的复杂性。当SQL其余编程语言结合后,把视图加入程序代码会比加入冗长、复杂、充满联接的查询更简单。
  2. 为数据库建立属兔,可用于改变底层表结构时以视图模仿数据库的原始结构,于是无需修改使用旧结构的应用程序。
  3. 建立视图能够隐藏读者无需看到的消息。
  4. 能够对视图进行增删改、约束等操做,这些操做会被写入原表,不过这须要包括NOT NULL的值,因此少这么干。

销毁视图

DROP VIEW pb_dimes;

事务

事务是一群能够完成一组工做的SQL语句。

START TRANSACTION;	--持续追踪后续全部SQL语句

COMMIT; --提交全部程序代码形成的改变

ROLLBACK;	--回滚,回到事务开始前

能够查看以建立的视图吗?

A:SHOW TABLES;

若是我卸载了有视图的表,会发生什么事?

A:看状况。有的RDBMS容许使用视图,但不返回数据。通常而言,最好先去除视图,而后再卸载它所依据的表。