[SQL系列] 从头开始学PostgreSQL 增删改查

什么是SQL

        SQL 是 Structured Query Language 的缩写,意为“结构化查询语言”,是一种专门用于管理关系型数据库的编程语言。它被广泛应用于数据库的查询、更新、删除和插入等操作,以及数据的统计、分析和报表生成等方面。SQL 语言具有简洁、灵活、强大和通用等特点,是数据库管理和数据分析的重要工具。
        SQL 语言的主要功能包括:
1. 定义数据库结构:可以通过 CREATE TABLE 语句来创建表格、索引和视图等数据库对象。
2. 查询数据:可以使用 SELECT 语句来查询表格中的数据,并可以使用各种聚合函数、排序和分组等操作来对数据进行统计和分析。
3. 更新数据:可以使用 INSERT、UPDATE 和 DELETE 语句来插入、更新和删除表格中的数据。
4. 控制权限:可以使用 GRANT 和 REVOKE 语句来授权和回收权限,以保护数据的安全性。
5. 事务处理:可以使用 EGIN、COMMIT 和 ROLLBACK 语句来实现事务的开始、提交和回滚等操作。
        SQL 语言的应用范围非常广泛,几乎所有的关系型数据库管理系统都支持 SQL 语言,如 MySQL、Oracle、SQL Server、PostgreSQL 等。同时,SQL 语言也成为了数据库开发和数据分析领域的标准语言,被广泛应用于各种企业、机构和组织的数据管理和分析工作。

        Mysql应该是现在学习资料最为全面,而且八股文最多的数据库了。所以我们选择PostSQL进行学习。

PostSQL

        介绍

        PostgreSQL(简称 PostSQL)是一个自由的开源对象 - 关系数据库服务器(数据库管理系统),它在灵活的 BSD-风格许可证下发行。它提供了相对于其他开放源代码数据库系统(如 MySQL 和 SQLite)以及专有系统(如 Oracle、Microsoft SQL Server 和 IBM DB2)的一种选择。PostgreSQL 支持多种编程语言和应用程序,并且可以处理各种类型的数据,包括文本、图像、音频和视频等。它具有强大的功能和灵活性,可以处理大规模数据集,并且可以快速地添加新的功能和模块。PostgreSQL 拥有一个庞大的社区,这个社区提供了大量的文档、教程和解决方案,使得 PostgreSQL 成为一种非常容易学习和使用的数据库管理系统。PostgreSQL 可以在各种操作系统上运行,包括 Windows、Linux 和 macOS 等。由于其不寻常的名字,有些人可能会停下来尝试拼读它,特别是那些把 PostgreSQL 拼读为 "PostgreSQL"。

        安装与使用

        这边为了不对操作系统有啥负担,建议还是使用docker进行安装       

docker run -itd --name postgres -e POSTGRES_PASSWORD=1234 -p 5432:5432 -d postgre

#如果要设置用户名的话加上参数
-e POSTGRES_USER=[用户名]

#如果要设置密码的话加上参数
-e POSTGRES_PASSWORD=[密码]

连接上docker里面的postgreSqL

docker exec -it postgres bash

切换到postgres账户,如果使用root的话无法进入 

su postgres

进入到数据库中: 

psql
#如果一开始写了用户名的话就
psql -U [username]

以下是一些常用的快捷键:

\q  退出 PostgreSQL。
\l  显示所有的数据库
\c  数据库名  从一个数据库切换到另一个数据库
\d  查看表结构
\di 查看索引
\ds: 显示当前数据库中的所有表的关系。
\dl: 显示当前数据库中的所有列。
\dt: 显示当前数据库中的所有表的详细信息。
\du: 显示当前数据库中的所有用户和其权限。
\lp: 列出当前数据库中的所有过程。
\lo: 列出当前数据库中的所有外键。
\mi: 显示当前数据库中的所有成员。
\mj: 显示当前数据库中的所有 Journal 日志。
\ms: 显示当前数据库中的所有存储过程。
\mt: 显示当前数据库中的所有触发器。
\mu: 显示当前数据库中的所有用户权限。
\mv: 显示当前数据库中的所有视图。
\ow: 显示当前数据库中的所有预定义函数。
\pat: 显示当前数据库中的所有派生类型。
\pgr: 显示当前数据库中的所有过程。
\pi: 显示当前数据库中的所有接口。
\ps: 显示当前数据库中的所有存储过程。
\pt: 显示当前数据库中的所有触发器。

创建用户:

create user test_user;

创建数据库:

create database testdb;

对应的删除数据库:

drop database testdb;

进入到数据库中:

\c testdb

建表:

create table mytable(id int, name varchar(255));

查看表:

\d mytable;

删除表格:

drop table mytable;

#如果要删除多个表
drop table table1, table2;

关于Schema

        在 PostgreSQL 数据库中,schema 是指在一个数据库内部创建的逻辑上的数据库,每个 schema 都有自己的命名空间,可以在同一个数据库内部创建多个 schema,每个 schema 可以包含不同的表、视图、存储过程等数据库对象。使用 schema 可以对数据库对象进行更好的组织和管理,同时也可以提高数据库的安全性和稳定性。

如果懂得C#的话,可以默认Schema是namespace。

创建schema

create schema myschema;

创建好 schema 之后,就可以在其中创建数据库对象,例如:

create table myschema.table(id int primary key, name varchar(20));

可以通过sql指令来查看下列的表格:

select * from myschema.table;

这时候如果要删除这个Schema的话:

 drop schema myschema;

会出现这样的结果:
ERROR:  cannot drop schema myschema because other objects depend on it
DETAIL:  table myschema."table" depends on schema myschema
HINT:  Use DROP ... CASCADE to drop the dependent objects too.

因此我们需要级联地删除,也就是顺便删除schema里面的所有对象

drop schema myschema cascade;

增删改查

增:Insert

为数据库新增数据,这边postgresql和其他的数据库差别不大,都是用的insert into

#先创建一个表
CREATE TABLE EMPLOYER(
   ID INT PRIMARY KEY     NOT NULL,
   NAME           TEXT    NOT NULL,
   AGE            INT     NOT NULL,
   ADDRESS        CHAR(50),
   SALARY         REAL,
   JOIN_DATE      DATE
);

#插入数据

INSERT INTO EMPLOYER(ID,NAME,AGE,ADDRESS,SALARY,JOIN_DATE) VALUES (1, 'Bob', 32, 'Beijing', 20000.00,'2001-01-01');

#设置一些Default属性
INSERT INTO EMPLOYER(ID,NAME,AGE,ADDRESS,SALARY,JOIN_DATE) VALUES (2, 'CC', 23, 'Shanghai', 20000.00, DEFAULT );

#插入多行
INSERT INTO EMPLOYER(ID,NAME,AGE,ADDRESS,SALARY,JOIN_DATE) VALUES (3, 'Dod', 25, 'Guangzhou ', 65000.00, '2007-02-03' ), (4, 'Eoe', 27, 'Shenzhen', 85000.00, '2011-11-11');

我们可以用Select指令来查看一下刚才插入的数据:

testdb=# select * from EMPLOYER;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  1 | Bob  |  32 | Beijing                                            |  20000 | 2001-01-01
  2 | CC   |  23 | Shanghai                                           |  20000 |
  3 | Dod  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  4 | Eoe  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(4 rows)

这时候可以注意,postgresql对于大小写是不敏感的,所以后续会使用小写。

删:Delete

#根据条件筛选,删除某一列
testdb=# delete from employer where id = 1;
DELETE 1
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
(3 rows)

这时候可以看待id为1的那一行已经被删除了。


#删除整张表
Delect from company

        在 PostgreSQL 数据库中,使用 DELETE 命令删除表时,不会自动释放表所占用的存储空间。相反,删除表只会删除表中的数据,而表结构和相关的索引、约束等对象仍然会保留在数据库中。
如果需要释放表所占用的存储空间,可以使用 DROP TABLE 命令:

drop table employer;

另外,如果表中的数据量较大,使用 DELETE 命令删除数据可能会导致性能问题。在这种情况下,可以使用 TRUNCATE 命令替代 DELETE 命令,例如:

truncate table employer;
Drop和Truncate的区别:        

Drop 和 Truncate 都是用于删除表的命令,但它们的作用和使用方式有一些不同。
        1. 删除数据的范围不同:
        Drop 命令会删除整个表,包括表结构和所有数据。而 Truncate 命令只删除表中的数据,不删除表结构。
        2. 执行方式不同:
        Drop 和 Truncate 都是 DDL 语句,执行后会自动提交。但是,Drop 命令是立即生效的,而         Truncate 命令在执行时会将数据放入回收站中,回收站中的数据可以在需要时进行恢复。
        3. 影响的对象不同:
        Drop 命令会删除表结构和所有相关的约束、触发器、索引等对象。而 Truncate 命令只删除表中的数据,不删除表结构和相关的对象。
        4. 安全性不同:
        Drop 和 Truncate 命令都需要谨慎使用,尤其是在没有备份的情况下。但是,Truncate 命令比 Drop 命令更安全,因为它只删除表中的数据,而不会影响表结构和相关对象。
        5. 执行速度不同:
        一般来说,Drop 命令的执行速度比 Truncate 命令快,因为 Drop 命令只需要删除表结构和相关对象,而 Truncate 命令需要删除表中的所有数据。
        总结起来,Drop 和 Truncate 命令都有各自的用途和优缺点,需要根据具体情况选择合适的命令来删除表。

改:Update

修改的方法是通过Update实现的,用法也很简单,如下

#通过where选择某一行,更新某一项

testdb=# update employer set salary = 100 where id = 3;
UPDATE 1
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  1 | Bob  |  32 | Beijing                                            |  20000 | 2001-01-01
  2 | CC   |  23 | Shanghai                                           |  20000 |
  4 | Eoe  |  27 | Shenzhen                                           |  85000 | 2011-11-11
  3 | Dod  |  25 | Guangzhou                                          |    100 | 2007-02-03
(4 rows)


#更新很多项,并且非空项全部更新(因为没有加上筛选条件),这边注意,CC原本就没有join_date,所以这边没更新

testdb=# update employer set address = 'BeiJing', salary=100000;
UPDATE 4
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  1 | Bob  |  32 | BeiJing                                            | 100000 | 2001-01-01
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
(4 rows)

查:Select

查询大多是通过Select加各种条件实现的,这边给一些简单的Demo

#如果要全选,就select *,但是如果只想选择对应的列就得都列出来
select ID, NAME, ADDRESS from EMPLOYER;

testdb=# select ID, NAME, ADDRESS from EMPLOYER;
 id | name |                      address
----+------+----------------------------------------------------
  1 | Bob  | Beijing
  2 | CC   | Shanghai
  3 | Dod  | Guangzhou
  4 | Eoe  | Shenzhen
(4 rows)


# Where条件
# 这边可以用算数运算符进行判定
testdb=# select * from EMPLOYER where SALARY > 20000;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  3 | Dod  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  4 | Eoe  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(2 rows)


#也可以用And or 或者not作为逻辑运算符号,比如
testdb=# select * from EMPLOYER where SALARY > 20000 and SALARY < 80000;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  3 | Dod  |  25 | Guangzhou                                          |  65000 | 2007-02-03
(1 row)


#也可以嵌套查询
testdb=# select * from employer where age > (select age from employer where salary > 65000);
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  1 | Bob  |  32 | Beijing                                            |  20000 | 2001-01-01
(1 row)

条件筛选

上面讲过了select * from table_name where 条件,这时候就是我们要筛选的条件。

往往我们筛选的条件会挺复杂的,因此SQL也会提供很多复杂的选择。

Like

Like条件筛选匹配两种符号,百分号%和下划线_

其中,百分号表示的是一个或者多个字符,而_表现的只有一个位置

#原始的表如下
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
(3 rows)

#比如我们想筛选数据库中20几岁的人,那么就用%
testdb=# select * from employer where age like '2%';
ERROR:  operator does not exist: integer ~~ unknown
LINE 1: select * from employer where age like '2%';
                                         ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
#这边需要用::text转一下


#使用%的话可以这么写
testdb=# select * from employer where age::text like '2%';
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
(3 rows)


testdb=# select * from employer where age::text like '2_';
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
(3 rows)

这边主要是因为年龄就两位,如果有两百岁的员工,那就没法用下划线筛选出来了。

Limit

Limit顾名思义,就是用于限制查询的数量,主要用于内容多的时候分页。我们先插入一些内容

这时候顺便引入一个概念,offset,偏移量。

比如我们有200页的内容,第一页只显示10行,就是

select * from table where [条件] limit 10;

那么我们要显示第二页的话就是

select * from table where [条件] limit 10 offset 10; 

这个offset就不包括前面的,从第11行开始。

#原本的表格扩张如下
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(5 rows)

#我们只筛选3行,并且还要从第二行开始
testdb=# select * from employer limit 3 offset 1;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
(3 rows)

Order by

排序,这个大家都很清楚了。一般来讲默认是Asc(升序),如果要降序的话就要加上Desc,我们直接来个例子

#原始的表格长这样
testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(5 rows)


#来个错误的案例,大家要注意,这边的order by是分开的,合在一起就错了。
testdb=# select * from employer orderby age;
ERROR:  syntax error at or near "age"
LINE 1: select * from employer orderby age;
                                       ^

#这边就按照年龄正序排序,和asc一样,但是不写默认就是asc,
testdb=# select * from employer order by age;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(5 rows)


#这边加上desc就是倒序排序了
testdb=# select * from employer order by age desc;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  2 | CC   |  23 | BeiJing                                            | 100000 |
(5 rows)


#当然不止如此,我们倒序排序之后还要根据薪资正序排序,就用逗号隔开
testdb=# select * from employer order by age desc, salary asc;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  2 | CC   |  23 | BeiJing                                            | 100000 |
(5 rows)

Group by

        Group by是用来分组的,一般用于select里面,对数据进行分组,我们看看例子。

testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(5 rows)

#要group by的项必须要在select里面
testdb=# select name, sum(salary) from employer group by name;
 name |  sum
------+--------
 Fof  |  65000
 Gog  |  85000
 Dod  | 100000
 Eoe  | 100000
 CC   | 100000
(5 rows)

#上面看起来不是很明显,我们换个组,因为上面有两个25, 两个27岁的,所以我们分组的话,就会合并在一起
testdb=# select age, sum(salary) from employer group by age;
 age |  sum
-----+--------
  25 | 165000
  27 | 185000
  23 | 100000
(3 rows)

#可以再加上order by 进行排序
testdb=# select age, sum(salary) from employer group by age order by age desc;
 age |  sum
-----+--------
  27 | 185000
  25 | 165000
  23 | 100000
(3 rows)

#也可以对计算的列进行排序
testdb=# select age, sum(salary) from employer group by age order by sum(salary);
 age |  sum
-----+--------
  23 | 100000
  25 | 165000
  27 | 185000
(3 rows)

With

with看起来有点像包装,就是有时候写嵌套语句的话太复杂,看起来很麻烦。我们先定义with作为通用表达式,然后就可以多次使用了。

#我们先用with定义一个叫做CTE的语句,这个语句筛选了employer里面的几个列
#第二行是如何使用这个CTE;

testdb=# with CTE as (select id, name, age, address from employer)
testdb-# select id, name from CTE;
 id | name
----+------
  2 | CC
  4 | Eoe
  3 | Dod
  5 | Fof
  6 | Gog
(5 rows)



testdb=# with move_rows as (delete from employer where salary >= 30000 returning *)
insert into company (select id, name, age, address, salary from move_rows);
INSERT 0 5
testdb=# select * from company;
 id | name | age |                      address                       | salary
----+------+-----+----------------------------------------------------+--------
  2 | CC   |  23 | BeiJing                                            | 100000
  4 | Eoe  |  27 | BeiJing                                            | 100000
  3 | Dod  |  25 | BeiJing                                            | 100000
  5 | Fof  |  25 | Guangzhou                                          |  65000
  6 | Gog  |  27 | Shenzhen                                           |  85000
(5 rows)

testdb=# select * from employer;
 id | name | age | address | salary | join_date
----+------+-----+---------+--------+-----------
(0 rows)

#这句话就是定义一个move_rows删除薪水大于3W的行,然后再插入到company表里

Having

having和where的效果其实差不多,但是having是和group by配合使用的

#原始表格
testdb=# select * from company;
 id | name | age |                      address                       | salary
----+------+-----+----------------------------------------------------+--------
  2 | CC   |  23 | BeiJing                                            | 100000
  4 | Eoe  |  27 | BeiJing                                            | 100000
  3 | Dod  |  25 | BeiJing                                            | 100000
  5 | Fof  |  25 | Guangzhou                                          |  65000
  6 | Gog  |  27 | Shenzhen                                           |  85000
(5 rows)

#通过having设定筛选条件
testdb=# select name from company group by name having sum(salary) > 80000;
 name
------
 Gog
 Dod
 Eoe
 CC
(4 rows)

#再来一个
testdb=# select address from company group by address having count(address) > 1;
                      address
----------------------------------------------------
 BeiJing
(1 row)

Distinct

去除重复,就有点像是set的操作,直接上

testdb=# select * from employer;
 id | name | age |                      address                       | salary | join_date
----+------+-----+----------------------------------------------------+--------+------------
  2 | CC   |  23 | BeiJing                                            | 100000 |
  4 | Eoe  |  27 | BeiJing                                            | 100000 | 2011-11-11
  3 | Dod  |  25 | BeiJing                                            | 100000 | 2007-02-03
  5 | Fof  |  25 | Guangzhou                                          |  65000 | 2007-02-03
  6 | Gog  |  27 | Shenzhen                                           |  85000 | 2011-11-11
(5 rows)

#对哪一列去重就写哪一列
testdb=# select distinct salary from employer;
 salary
--------
  85000
  65000
 100000
(3 rows)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值