数据库


概念性内容

使用文件系统存储数据的缺点

数据库管理系统 (DBMS) 的优缺点

优点
缺点

数据定义语言 (DDL)

数据操纵语言 (DML)

ER 图

ER 图是设计数据库的关键

基数比

基数,意思就是这一列的所有值,如果扔到一个集合里面去,集合大小是多少。

对于二元关系,基数比可以是:

image-20220928232444081

SQL 注入攻击

比如,在一个 web 页面当中,用户搜索一个产品名字,然后 Perl 查询 SQL 返回对应信息。假如 Python 代码是这样写的:

user_input = input("请输入产品名称: ")

query = f"SELECT * FROM products WHERE name = '{user_input}'"

print("生成的SQL查询:", query)

现在,如果用户输入的是正常的产品名称,比如product1,那么生成的SQL查询将是正常的:

SELECT * FROM products WHERE name = 'product1'

但是,如果用户输入恶意代码,例如' OR '1'='1,则生成的SQL查询变为:

SELECT * FROM products WHERE name = '' OR '1'='1'

这将导致查询返回表中所有的记录,因为 '1'='1' 总是为真。

防御方法:

JOIN 类型

数据库标准化

标准化数据表,有以下功效

例子:

比如这个表,有一大堆的重复数据

img

为了避免重复,可以考虑把这个大的表,拆分成三个小的表,然后这三个表通过主键(外键)联系起来

img

First normal form(一阶范式)

  1. 每个 field 只包含最小单位的有意义的值。比如,姓名拆成姓和名。
  2. 表不包含重复的 groups of fields,同一个 field 不包含重复的数据

对于第一个条件(每个列不能包含多个值),可以这样修改(上表不满足条件,下表满足)

img

但是虽然下面那张表满足了第一个条件,仍然不满足第二个条件。比如如果新增了一个 WH E,所有的行都要发生改动。相当于,repeating fields. 所以应该进一步改成这样:

img

但是主键也要修改。之前的主键是 PART 一个属性,现在的主键是 (Part, WH) 二元组。

Second normal form(二阶范式)

二阶范式,是一阶的加强版。

  1. usually used in tables with a multiple-fieled primary key(composite key)
  2. 每一个 non-key field 都跟整个主键有关系
  3. 每一个与主键无关的东西,都放在别的表里面

主要就是,用多个表,消除表当中的冗余数据(redundant data)

像这个表,不满足二阶范式。

img

发现 WH B 出现了两次,且对应的地址(address)相等。这就意味着表格出现了冗余数据,要拆表。所有的 WH 只要编号相同,地址应当也是相同的。所以可以把地址拆出去,用 WH 作为主键连接:

img

这样,就满足二阶范式了。

Third normal form(三阶范式)

三阶范式,仅考虑主键只有一列的表。

  1. 表当中,通常使用 single-field primary key
  2. 记录 do not depend on anything other than 主键
  3. 每一个 non-key field is a fact about the key

来看一个不满足三阶范式的例子

img

在这个表当中,DeptName 跟主键 EmpNo 好像没啥关系,只跟 WorkDept 有关。所以 DeptName 应该拆到别的表当中去。

img


语法部分

CREATE 语句

CREATE TABLE <table name> (
    <column name> <data type> [(<size>)] <column constraint>,
    ...
    <keys>
);
数据类型 (<data type>)
列约束 (<column constraint>)
键定义 (<keys>)

SELECT 语句

SELECT <column name1>, [<column name2>, ...]
FROM <table name>
[WHERE <expr>];
[count()] -- 返回行数
[ORDER BY <column name> <method>(asc, desc)] -- 排序方式

实用函数

时间和日期处理

field可以是century, day, decade, dow(星期天是第0天), doy(一年的第几天) ···

匹配语法

Note

正则表达式要记得使用^来表示开始和使用$来表示结尾

可参考 [官方文档](https://www.postgresql.org/docs/current/functions-matching.htm)

GROUP BYORDER BY 关键字

把所有属性值相同的行放在一起,再按照这个值排序,统计每个属性有多少行

SELECT <colName1>, <colName2>, COUNT(*)
FROM <tableName>
[WHERE <condition>]
GROUP BY <colName1>, <colName2>
HAVING <aggFunc()> <condition> -- HAVING 语法, 用aggregate函数
ORDER BY <colName1>, <colName2>;

列别名和表别名

SELECT Guest.dob AS "date of brith" 
FROM <tableName> AS "Guest";
ORDER BY Guest.dob DESC;

Note

这里需要双引号,字符串,时间戳等都是单引号

aggregate 函数

SELECT Region as RegionName, SUM(Pop2015) as TotalPopulation2015
    FROM PopulationEU
    GROUP BY Region
    ORDER BY TotalPopulation2015 desc;

例子:

INSERT 语句

INSERT INTO <tableName> (<column list>) VALUES (<value list>);

DROP TABLE 删除表

DROP TABLE IF EXISTS <tableName>;

DELETE 语句

DELETE FROM <tableName> WHERE <conditions>;  # 删满足条件的
DELETE FROM <tableName>;                     # 全部删除

ALTER TABLE修改表

ALTER TABLE <tableName> RENAME TO <newName>; -- 改表名
ALTER TABLE <tableName> RENAME COLUMN <oldColName> TO <newColName>; -- 改列名 
ALTER TABLE <tableName> DROP COLUMN <colName>; -- 删除列
ALTER TABLE <tableName> ADD COLUMN <colName> <colType>; -- 新增列
ALTER TABLE <tableName> ALTER COLUMN <colName> TYPE <newColType>; -- 修改列的类型
ALTER TABLE <tableName> ADD PRIMARY KEY <colName>; -- 增加主键

UPDATE 命令

UPDATE <tableName>
    SET
        <colName1> = {<expr1>},
        <colName2> = {<expr2>},
        <colName3> = {<expr3>},
        ...
    [WHERE <coldition>];

事务控制

BEGIN TRANSACTION;
-- blabla
COMMIT;
END TRANSACTION;
-- 正常执行

BEGIN;
-- blabla
ROLLBACK;
-- 回滚

JOIN 语句

SELECT table1.<colName>, table1.<colName>, ···
FROM <tableName1> AS table1
JOIN <tableName2> AS table2 ON table2.<colName> = table1.<colName>
JOIN <tableName3> AS table3 ON table3.<colName> = table1.<colName>;

视图创建

CREATE VIEW viewname AS
    SELECT field1, field2, field3, ..., FROM table1, table2
    WHERE ;

SQL 表集合

SELECT DISTINCT salary FROM tableName; -- 去除重复

(SELECT DISTINCT Pnumber
FROM PROJECT, DEPARTMENT, EMPLOYEE
WHERE Dnum = Dnumber AND Mgr_ssn = Ssn
AND Lname = 'Smith')

UNION

(SELECT DISTINCT Pnumber
FROM PROJECT, WORKS_ON, EMPLOYEE
WHERE Pnumber = Pno AND Essn = Ssn
AND Lname = 'Smith'); -- 并集

SELECT emp_name, salary
FROM employees e1
WHERE salary > ALL (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e2.department = e1.department
    GROUP BY department
); -- 比较运算符