数据库基础小记

第一章

数据库

1 创建CREATE DATABASE

CREATE DATABASE db_mr;
CREATE SCHEMA db_admin1;

2 创建指定字符集的数据库

CHARACTER SET = utf8;

COLLATE utf8_general_ci;
DROP DATABASE IF EXISTS db_mr;
SHOW DATABASES LIKE 'db_%';

3 SHOW命令查看MySQL服务器中的所有数据库信息


SHOW DATABASES|SCHEMAS
[LIKE '模式' WHERE 条件];

SHOW DATABASES like 'db_%'
SHOW DATABASES like 'db_'

4 选择数据库

CREATE DATABASE 语句创建数据库后,该数据库 并不会自动成为 当前数据库。若想让它
成为当前数据库,需要使用 MySQL 提供的 USE语句来实现
use 库名

5 修改数据库


可以修改被创建数据库的相关参数
ALTER DATABASE或者ALTER SCHEMA语句

ALTER DATABASE | SCHEMA 数据库名
DEFAULT CHARACTER SET = 字符集
DEFAULT COLLATER = 较对规则名称

6 删除数据库

DROP DATABASE 或者 DROP SCHEMA
语句的语法格式如下:
DROP DATABASE|SCHEMA IF EXISTS 数据库名;

创建数据表

创建数据表使用 CREATE TABLE 语句。语法如下:
 
CREATE TEMPORARY TABLE IF NOT EXISTS 数据表名
[(create_definition,…)][table_options] [select_statement]

但,在实际中使用最基本的格式即可,具体格式如下:
CREATE TABLE 数据表名(列名1 属性,列名2 属性…);

数据表

任务:

创建一个名为 bigdata 的数据库,并在该数据库中创建一个名为 stu_table 的数据表,该表
包括字段 id , usr, password, createtime ,定义时指明类型,哪个是主键,是否自动编
号,是否可以为空等。

1 查看表结构 SHOW COLUMNS

使用 SHOW COLUMNS 语句查看
MySQL 中,使用 SHOW COLUMNS 语句可以查看表结构, SHOW COLUMNS 语句的基
本语法格式如下:
SHOW [FULL] COLUMNS FROM 数据表名 [FROM 数据库名];
或
SHOW [FULL] COLUMNS FROM 数据表名.数据库名;

使用 DESCRIBE 语句查看
MySQL 中,还可以使用 DESCRIBE 语句查看数据表结构。 DESCRIBE 语句的基本语法格
式如下:
DESCRIBE 数据表名;
其中, DESCRIBE 可以简写成 DESC 。在查看表结构时,也可以只列出某一列的信息。其语
法格式如下:
DESCRIBE 数据表名 列名;

2 修改表结构

ALTER [IGNORE] TABLE 数据表名 alter_spec[,alter_spec]...| table_options

IGNORE可选项,如果出现重复关键行,则只执行一行,其他重复的行被删除。
alter_spec子句:用于定义要修改的内容。

添加新字段及修改字段定义
MySQL ALTER TABLE 语句中,可以通过使用如下子句来添加新字段:
ADD [COLUMN] create_definition [FIRST | AFTER column_name ]
使用如下子句可以修改已定义字段的定义:
MODIFY [COLUMN] create_definition

任务1:

添加一个新的字段 email, 类型为可变字符,最大长度 50 ,非空, user 字段的类型由可变
字符长度 30 ,改为长度 40.
修改字段名
MySQL ALTER TABLE 语句中,使用如下子句可以修改字段名或者字段类型:
CHANGE [COLUMN] old_col_name create_definition

任务2

将数据表 stu_table 的字段名 user 修改为 username.
删除字段
MySQL ALTER TABLE 中,使用如下子句可以删除指定字段:
DROP [COLUMN] col_name

任务3

将数据表 stu_table 中的字段 email 删除 .
修改表名
MySQL ALTER TABLE 中,使用如下子句可以修改表名:
RENAME [AS] new_tbl_name

任务4

将数据表 stu_table 名更改为 stu_tableold.

3 重命名表

MySQL 中, 重命名数据表 可以使用 RENAME TABLE 语句来实现。
RENAME TABLE 语句的基本语法格式如下:
RENAME TABLE 数据表名1 To 数据表名2

4 复制表

创建表的 CREATE TABLE 命令还有另外一种语法结构,在一张已经存在的数据表的基础上
创建一份该表的拷贝,也就是复制表。
这种用法的语法格式如下:
CREATE TABLE [IF NOT EXISTS] 数据表名
{LIKE 源数据表名 | (LIKE 源数据表名)}

如果在复制表的时候,也同时复制其中的内容,可用如下命令实现:
CREATE TABLE news3 AS SELECT * FROM news;

5 删除表

删除数据表的操作很简单,同删除数据库的操作类似,使用 DROP TABLE 语句即可实现。
DROP TABLE语句的基本语法格式如下:
DROP TABLE [IF EXISTS] 数据表名;

数据表小结

1. 如何创建数据表、查看数据结构、修改表结构、重命名表、复制表和删除表
2. 创建表和修改表很重要,且容易出现语法错误,需要多练习
3. 创建表和修改表后,一定要查看表结构,以确保操作是否正确
4. 删除表要特别小心,因为删除表同时也会删除表中的所有数据

MySQL存储引擎

存储引擎其实就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等
技术的实现方法。
因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型
(即存储和操作此表的类型)。
Oracle SQL Server 等数据库中只有一种存储引擎,所有数据存储管理机制都是一样
的。而 MySql 数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同
的存储引擎,用户也可以根据自己的需要编写自己的存储引擎。

查询MySQL中支持的存储引擎

1 .查询支持的全部存储引擎
MySQL 中,可以使用 SHOW ENGINES 语句查询 MySQL 中支持的存储引擎。其查询语句
如下:
SHOW ENGINES;
2 .查询默认的存储引擎
如何想要知道当前 MySQL 服务器采用的默认存储引擎是什么,可以通过执行 SHOW
VARIABLES 命令来查看。查询默认的存储引擎的 SQL 如下:
SHOW VARIABLES LIKE 'storage_engine%';

小知识理解:主键、外键

主键保证了数据的唯一性,外键保证了数据的完整性。
主键是能确定一条记录的唯一标识,比如,一条记录包括身份正号,姓名,年龄。 身份
证号 是唯一能确定你这个人的,其他都可能有重复,所以, 身份证号 是主键。
外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性。
比如, A 表中的一个字段,是 B 表的主键,那他就可以是 A 表的外键。

MySQL数据类型

MySQL 数据库中,每一条数据都有其数据类型。 MySQL 支持的数据类型,主要分成 3
类: 数字类型、字符串(字符)类型、日期和时间 类型。

1 数字类型

MySQL 支持所有的 ANSI/ISO SQL 92 数字类型。这些类型包括准确数字的数据类型
NUMERIC DECIMAL INTEGER SMALLINT ),还包括近似数字的数据类型
FLOAT REAL DOUBLE PRECISION )。其中的关键词 INT INTEGER 的同义词,关键
DEC DECIMAL 的同义词。

2 字符串类型

字符串类型可以分为 3 类:普通的文本字符串类型( CHAR VARCHAR )、可变类型
TEXT BLOB )和特殊类型( SET ENUM )。它们之间都有一定的区别,取值的范围
不同,应用的地方也不同。

3 日期和时间数据类型

日期和时间类型包括: DATETIME DATE TIMESTAMP TIME YEAR 。其中的每种类型
都有其取值的范围,如赋予它一个不合法的值,将会被 “0” 代替。

第二章

基本查询语句 SELECT

1 SELECT语句的基本语法

select selection_list from 数据表名 where primary_constraint group by grouping_columns 
order by sorting_cloumns //如何对结果进行排序
having secondary_constraint //查询时满足的第二条件
limit count //限定输出的查询结果

2 查询表中的一列或多列

3 从一个表或多个表中获取数据

select 表名+列名 ......

单表查询

单表查询是指从一张表中查询所需要的数据 , 所有查询操作都比较简单。
查询所有字段
查询指定字段
查询指定数据
IN 关键字的查询
BETWEEN AND 查询
LIKE 的字符匹配查询
IS NULL 关键字查询空值
AND 的多条件查询
OR 的多条件查询
DISTINCT 关键字去除结果中的重复行
ORDER BY 关键字对查询结果排序
GROUP BY 关键字分组查询
LIMIT 限制查询结果的数量

2.1 查询所有字段

查询所有字段是指查询表中所有字段的数据。这种方式可以将表中所有字段的数据都查
询出来。在 MySQL 中可以使用 “*” 代表所有的列,即可查出所有的字段,语法格式如下:
SELECT * FROM 表名

2.2 查询指定字段

查询指定字段可以使用下面的语法格式:
SELECT 字段名 FROM 表名;

2.3 查询指定数据 WHERE

如果要从很多记录中查询出指定的记录,那么就需要一个查询的条件。设定查询条件应
用的是 WHERE 子句。通过它可以实现很多复杂的条件查询。在使用 WHERE 子句时,需要
使用一些比较运算符来确定查询的条件。

2.4 IN关键字的查询

IN 关键字可以判断某个字段的值是否在于指定的集合中。 如果字段的值在集合中,则满
足查询条件,该记录将被查询出来 ;如果不在集合中,则不满足查询条件。其语法格式
如下:
SELECT * FROM 表名 WHERE 条件 [NOT] IN(元素1,元素2,…,元素n);

2.5 BETWEEN AND的范围查询

BETWEEN AND 关键字可以 判断某个字段的值是否在指定的范围内 。如果字段的值在指定
范围内,则满足查询条件,该记录将被查询出来。如果不在指定范围内,则不满足查询
条件。其语法如下:
SELECT * FROM 表名 WHERE 条件 [NOT] BETWEEN 取值1 AND 取值2

2.6 LIKE的字符匹配查询

LIKE 属于较常用的比较运算符,通过它可以实现 模糊查询 。它有两种通配符:
“%”和下划线“_”

一、%

  表示任意0个或多个字符,可匹配任意类型和长度的字符。有些情况下是中文,需用两个百分号(%%)表示

 :

  1. 将 u_name 为“张三”、“张猫三”、“三脚猫”、“唐三藏”等有“三”的记录全找出来
    SELECT * FROM [user] WHERE u_name LIKE ‘%三%’
    
  2. 如果须要找出 u_name 中既有“三”又有“猫”的记录,请运用 and 条件
    SELECT * FROM [user] WHERE u_name LIKE ‘%三%’ AND u_name LIKE ‘%猫%’
    
  3. 虽然能搜索出“三脚猫”,但不能搜索出符合条件的“张猫三”
    SELECT * FROM [user] WHERE u_name LIKE ‘%三%猫%’
    
    二、 _

      表示任意单个字符。匹配单个任意字符,它常用来限定表达式的字符长度语句

     

  4. 只找出“唐三藏”这样 u_name 为三个字且中间一个字是“三”的;
    SELECT * FROM [user] WHERE u_name LIKE ‘三’
    

  5. 只找出“三脚猫”这样 name 为三个字且第一个字是“三”
    ​
    SELECT * FROM [user] WHERE u_name LIKE ‘三__’;
    
    ​
三、[ ]

  表示括号内所列字符中的一个(类似正则表达式)。指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个

 :

  1. 找出“张三”、“李三”、“王三”(而非“张李王三”);
    SELECT * FROM [user] WHERE u_name LIKE ‘[张李王]三’
    
  2. SELECT * FROM [user] WHERE u_name LIKE ‘老[1-9]’
    
    四、[^]

      表示不在括号所列之内的单个字符。其取值和 [ ] 相同,但它要求所匹配对象为指定字符以外的任一个字符

     :

  3. 将找出不姓“张”、“李”、“王”的“赵三”、“孙三”等;
    SELECT * FROM [user] WHERE u_name LIKE ‘[^张李王]三’
    
    排除“老1”到“老4”,寻找“老5”、“老6”、……
    SELECT * FROM [user] WHERE u_name LIKE ‘老[^1-4]’;
    

2.7 IS NULL关键字查询空值

IS NULL 关键字可以用来判断字段的值是否为空值( NULL )。如果字段的值是空值,则
满足查询条件,该记录将被查询出来。如果字段的值不是空值,则不满足查询条件。其
语法格式样如下:
IS [NOT] NULL

mysql> SELECT books,row FROM tb_book WHERE row IS NULL;
+----------------------+------+
| books | row |
+----------------------+------+
| Java范例完全自学手册 | NULL |
| Android从入门到精通 | NULL |
+----------------------+------+
2 rows in set (0.00 sec)

2.8 带关键字AND的多条件查询

AND 关键字可以用来联合多个条件进行查询。使用 AND 关键字时,只有 同时满足所有查
询条件 的记录会被查询出来。如果不满足这些查询条件的其中一个,这样的记录将被排
除掉。
AND 关键字的语法格式如下:
select * from 数据表名 where 条件1 and 条件2 […AND 条件表达式n];

2.9 OR的多条件查询

OR 关键字也可以用来联合多个条件进行查询,但是与 AND 关键字不同, OR关键字只要
满足查询条件中的一个,那么此记录就会被查询出来 ;如果不满足这些查询条件中的任
何一个,这样的记录将被排除掉。 OR 关键字的语法格式如下:
select * from 数据表名 where 条件1 OR 条件2 […OR 条件表达式n];

2.10 DISTINCT关键字去除结果中的重复行

使用 DISTINCT 关键字可以去除查询结果中的重复记录,语法格式如下:
select distinct 字段名 from 表名;

2.11 ORDER BY关键字对查询结果排序

使用 ORDER BY 可以对查询的结果进行升序( ASC )和降序( DESC )排列,在 默认情况
下,ORDER BY按升序 输出结果。如果要按降序排列可以使用 DESC 来实现。语法格式如
下:
ORDER BY 字段名 [ASC|DESC];

2.12 GROUP BY关键字分组查询

通过 GROUP BY 子句可以 将数据划分到不同的组中,实现对记录进行分组查询。
在查询时,所查询的列必须包含在分组的列中,目的是使查询到的数据没有矛盾。
GROUP BY 通常与聚合函数一起使用。

GROUP_CONCAT()函数

函数语法:
group_concat( [DISTINCT] 要连接的字段 [Order BY 排序字段 ASC/DESC] [Separator ‘分
隔符’] )
该函数返回带有来自一个组的连接的非 NULL 值的字符串结果
通俗点理解: group_concat() 会计算哪些行属于同一组,将属于同一组的列显示出来。要
返回哪些列,由函数参数 ( 就是字段名 ) 决定。分组必须有个标准,就是根据 group by 指定
的列进行分组。

GROUP BY GROUP_CONCAT()函数一起使用

使用关键字 GROUP BY GROUP_CONCAT() 函数查询,可以将每个组中的所有字段值都
显示出来。

user, talk 只要有一个不相同就会分一个组

mysql> select * from tb_book;
+----+----------------------+----------+--------+------+--------+
| id | books | talk | user | row | sort |
+----+----------------------+----------+--------+------+--------+
| 1 | PHP开发典型模块大全 | Java | mr | 12 | 模块类 |
| 2 | Java项目开发全程实录 | Java | mrsoft | 95 | 项目类 |
| 3 | Java Web从入门到精通 | Java Web | lx | 1 | 基础类 |
| 4 | Java范例完全自学手册 | Java | mr | NULL | 范例类 |
| 27 | Android从入门到精通 | Android | mr | NULL | 基础类 |
+----+----------------------+----------+--------+------+--------+
5 rows in set (0.00 sec)
mysql> select id, books,talk, user from tb_book group by user,talk;
+----+----------------------+----------+--------+
| id | books | talk | user |
+----+----------------------+----------+--------+
| 3 | Java Web从入门到精通 | Java Web | lx |
| 27 | Android从入门到精通 | Android | mr |
| 1 | PHP开发典型模块大全 | Java | mr |
| 2 | Java项目开发全程实录 | Java | mrsoft |
+----+----------------------+----------+--------+
4 rows in set (0.04 sec)

2.13 LIMIT限制查询结果的数量

查询数据时,可能会查询出很多的记录。而用户需要的记录可能只是很少的一部分。这
样就需要来 限制查询结果的数量 LIMIT MySQL 中的一个特殊关键字。 LIMIT 子句可以
对查询结果的记录条数进行限定,控制它输出的行数。

还可以用 LIMIT 从查询结果的中间部分取值。需要定义两个参数,第 1 个参数是开始读取
的第一条记录的编号(查询结果中,第一个记录的编号是 0 ,非 1 );第 2 个参数是要查询
的记录的个数。

3. 聚合函数查询

聚合函数的最大特点是它们根据一组数据求出一个值。
聚合函数的结果值只根据选定行中非 NULL 的值进行计算, NULL 值被忽略。
COUNT()函数
SUM()函数
AVG()函数
MAX()函数
MIN()函数

3.1 COUNT()函数

COUNT() 函数,对于除 “*” 以外的任何参数,返回所选择集合中非NULL值的行的数目;
对于参数“*”,返回选择集合中所有行的数目,包含NULL 值的行。没有 WHERE 子句的
COUNT(*) 是经过内部优化的,能够快速的返回表中所有的记录总数。

3.2 SUM()函数

SUM() 函数可以求出表中某个字段取值的总和。

3.3 AVG()函数

AVG() 函数可以求出表中某个字段取值的平均值。
mysql> select avg(row) from tb_book;
+----------+
| avg(row) |
+----------+
| 36.0000 |
+----------+
1 row in set (0.00 sec)

3.4 MAX()函数

MAX() 函数可以求出表中某个字段取值的最大值。
mysql> select max(row) from tb_book;
+----------+
| max(row) |
+----------+
| 95 |
+----------+
1 row in set (0.01 sec)

3.5 MIN()函数

MIN() 函数可以求出表中某个字段取值的最小值。
mysql> select min(row) from tb_book;
+----------+
| min(row) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)

4.高级查询

4.1 连接查询

  连接是把不同表的记录连到一起的最普遍的方法。
一种错误的观念认为由于MySQL的简单性和源代码开放性,使它不擅长连接。
MySQL从一开始就能够很好地支持连接,现在还以支持标准的 SQL92连接语句而自夸,
这种连接语句可以以多种高级方法来组合表记录。  
4.1.1内连接查询

内连接是最普遍的连接类型,而且是最匀称的,因为它们要求构成连接的每一部分的每
个表的匹配,不匹配的行将被排除。最常见的就是相等连接,也就是连接后的表中某个
字段与每个表中的都相同。
select A表列名1,B表列名2 from 表1,表2 where A表.列名=B表.列名

4.1.2外连接查询

与内连接不同,外连接是指使用 OUTER JOIN 关键字将两个表连接起来。外连接生成的结
果集不仅包含符合连接条件的行数据,而且还包括 左表 (左外连接时的表)、 右表 (右
外连接时的表)或 两边连接表 (全外连接时的表)中所有的数据行。语法如下:
左外连接( LEFT JOIN )是指将左表中的所有数据分别与右表中的每条数据进行连接组
合,返回的结果除内连接的数据外,还包括左表中不符合条件的数据,并在右表的相应
列中添加 NULL 值。
SELECT columns
FROM left_table
LEFT JOIN right_table ON left_table.common_column = right_table.common_column;
SELECT columns
FROM left_table
RIGHT JOIN right_table ON left_table.common_column = right_table.common_column;
4.1.3复合条件连接查询

SELECT columns
FROM table1
JOIN table2 ON (condition1 AND condition2)

4.2子查询

IN关键字子查询
SELECT employee_name
FROM employees
WHERE department_id IN (SELECT department_id FROM departments WHERE location_id = 1000);

带比较运算符的子查询
SELECT product_name, price
FROM products
WHERE price > (SELECT AVG(price) FROM products);

EXISTS关键字的子查询(不满足就不执行)
SELECT department_name
FROM departments d
WHERE EXISTS (SELECT * FROM employees e WHERE e.department_id = d.department_id);

ANY关键字的子查询(不满足就不执行)
SELECT employee_name, salary
FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 10);

ALL关键字的子查询(不满足就不执行)
SELECT employee_name, salary
FROM employees
WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 20);

4.3合并查询结果

UNIONUNION ALL 是 SQL 中用来合并多个查询结果的操作符,但它们之间有一些关键区别:

  1. 去重

    • UNION 会自动去除重复的记录,只返回唯一的结果集。
    • UNION ALL 则会返回所有记录,包括重复的记录。
  2. 性能

    • 因为 UNION 需要检查并去除重复记录,它的性能通常比 UNION ALL 要差,尤其是在处理大型数据集时。
    • UNION ALL 不进行去重检查,因此执行速度较快。
  3. 使用场景

    • 如果你需要确保结果中没有重复的记录,应该使用 UNION
    • 如果你需要保留所有记录,包括重复的,或者在你确信结果集中不会有重复时,可以使用 UNION ALL

4.4定义表和字段的别名

在查询时,可以为表和字段取一个别名,这个别名可以代替其指定的表和字段。
为字段和表取别名,能够使查询更加方便。而且可以使查询结果以更加合理的方式显
示。
为表取别名
为字段取别名

1. 给列起别名

SELECT column_name AS alias_name FROM table_name;

示例:

SELECT first_name AS "First Name", last_name AS "Last Name" FROM employees;

2. 给表起别名

SELECT a.column_name FROM table_name AS a;

示例:

SELECT e.first_name, e.last_name FROM employees AS e;

3. 在聚合函数中使用

SELECT COUNT(*) AS total_employees FROM employees;

4. 在JOIN语句中使用

SELECT a.column_name, b.column_name FROM table_a AS a JOIN table_b AS b ON a.id = b.a_id;

4.5使用正则表达式查询

MySQL 使用 REGEXPRLIKE 来进行正则表达式匹配。

示例:查找包含数字的名字

SELECT name FROM employees WHERE name REGEXP '[0-9]';

Oracle 提供了 REGEXP_LIKE 函数用于正则表达式的匹配。

示例:查找包含特定模式的电子邮件地址

SELECT email FROM users WHERE REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$');

5 函数

1. 常用函数

MySQL函数
数学函数
数学函数是 MySQL 中常用的一类函数。其主要用于处理数字,包括整型和浮点数等等。
ABS(X)函数
FLOOR(X)函数
RAND()函数
PI()函数
TRUNCATE(X,Y)函数
练习
SELECT TRUNCATE(1.31,1), TRUNCATE(1.99,1), TRUNCATE(1.99,0), TRUNCATE(19.99,-1);
ROUND{(X)和(X,Y)}函数
练习

1】使用ROUND(x)函数对操作数进行四舍五入操作,输入语句如下:

SELECT ROUND(-1.14),ROUND(-1.67), ROUND(1.14),ROUND(1.66);

2】使用ROUND(x,y)函数对操作数进行四舍五入操作,结果保留小数点后面指定y位,

输入语句如下:

SELECT ROUND(1.38, 1), ROUND(1.38, 0), ROUND(232.38, -1), round(232.38,-2);

SQRT(X)函数

字符串函数

字符串函数是MySQL中最常用的一类函数,主要用于处理表中的字符串。

INSERT(s1,x,len,s2)函数
UPPER(s),UCASE(s)函数
LOWER(s),LCASE(s)函数
LEFT(s,n)函数
RIGHT(s,n)函数
CONCAT()函数
CONCAT_WS()函数
RTRIM(s)函数
RTRIM(s)函数将去掉字符串s结尾处(右边)的空格。
SUBSTRING(s,n,len)函数

SUBSTRING(s,n,len)函数从字符串s的第n个位置开始获取长度为len的字符串。

REVERSE(s)函数

REVERSE(s)函数将字符串s的顺序反过来。

FIELD(s,s1,s2,…)

FIELD(s,s1,s2,…)函数返回第一个与字符串s匹配的字符串的位置。

LOCATE(s1,s)POSITION(s1 IN s)INSTR(s,s1)函数

MySQL中,可以通过LOCATE(s1,s)POSITION(s1 IN s)INSTR(s,s1)函数获取子字符串

相匹配的开始位置。这3个函数的语法格式如下。

日期和时间函数

日期和时间函数是MySQL中另一最常用的函数, 主要用于对表中日期和时间数据的处理。

CURDATE()CURRENT_DATE()函数

获取当前日期。

CURTME()CURRENT_TIME()

获取当前时间。

NOW()

NOW()函数获取当前日期和时间。还有CURRENT_TIMESTAMP()函数、LOCALTIME()

数、SYSDATE()函数和LOCALTIMESTAMP()函数也同样可以获取当前日期和时间。

DATEDIFF(d1,d2)
DATE_FORMAT() 

DATE_FORMAT() 函数用于以不同的格式显示日期/时间数据。

DATE_FORMAT(date,format)
date 参数是合法的日期。format 规定日期/时间的输出格式。

ADDDATE(d,n)
ADDDATE(d,INTERVAL expr type)

ADDDATE(d,n) 用于返回起始日期 d 加上n天的日期。
SUBDATE(d,n)
练习
1 】使用 DATE_SUB SUBDATE 函数执行日期减操作,输入语句如下:
SELECT DATE_SUB('2011-01-02', INTERVAL 31 DAY) AS col1,
SUBDATE('2011-01-02', INTERVAL 31 DAY) AS col2,
DATE_SUB('2011-01-01 00:01:00',INTERVAL '0 0:1:1' DAY_SECOND) AS col3;
2 】使用 ADDTIME 进行时间加操作,输入语句如下:
SELECT ADDTIME('2000-12-31 23:59:59','1:1:1'), ADDTIME('02:02:02', '02:00:00’);
3 】使用 SUBTIME() 函数执行时间减操作,输入语句如下:
SELECT SUBTIME('2000-12-31 23:59:59','1:1:1'), SUBTIME('02:02:02','02:00:00');
条件判断函数
系统信息函数

系统信息函数用来查询 MySQL 数据库的系统信息。
获取 MySQL 版本号、连接数和数据库名的函数
获取用户名函数
获取字符串的字符集合排序方式的函数
获取MySQL版本号、连接数和数据库名的函数
VERSION() 函数返回数据库的版本号; CONNECTION_ID() 函数返回服务器的连接数,也
就是到现在为止 MySQL 服务的连接次数; DATABASE() 和SCHEMA()返回当前数据库名。
获取用户名的函数
USER() SYSTEM_USER() SESSION_USER() CURRENT_USER() CURRENT_USER
这几个函数可以返回当前用户的名称。
获取字符串的字符集和排序方式的函数
CHARSET(str) 函数返回字符串 str 的字符集,一般情况下这个字符集就是系统的默认字符
集; COLLATION(str) 函数返回字符串str的字符排列方式。
加密函数

加密函数是 MySQL 中用来对数据进行加密的函数。因为数据库中有些很敏感的信息不希
望被其他人看到,所以就可以通过加密的方式来使这些数据变成看似乱码的数据。
加密函数PASSWORD(str)
PASSWORD(str) 函数可以对字符串 str 进行加密。
一般情况下,PASSWORD(str)函数主要是用来给用户的密码加密的。
加密函数MD5(str)
MD5(str) 函数可以对字符串 str 进行加密, 主要对普通的数据进行加密。
其他函数

MySQL 中除了上述内置函数以外,还包含很多函数。例如,数字格式化函数
FORMAT(x,n) IP 地址与数字的转换函数 INET_ATON(ip) ,还有加锁函数
GET_LOCT(name,time) 、解锁函数 RELEASE_LOCK(name) 等等。
格式化函数FORMAT(x,n)
FORMAT(x,n) 函数可以将数字 x 进行格式化,将 x 保留到小数点后 n 位。这个过程需要进行
四舍五入。
改变字符集的函数
CONVERT(s USING cs) 函数将字符串 s 的字符集变成cs。
改变字段数据类型的函数
CAST(x AS type) CONVERT(x, type) 这两个函数将 x 变成 type 类型。这两个函数只对
BINARY CHAR DATETIME TIME SIGNED INTEGER UNSIGNED INTEGER 这些类型
起作用。但两种方法只是改变了输出值的数据类型,并没有改变表中字段的类型。

6 数据备份

备份数据是数据库管理最常用的操作。为了保证数据库中数据的安全,数据管理员需要
定期的进行数据备份。一旦数据库遭到破坏,即通过备份的文件来还原数据库。
使用 mysqldump 命令备份
直接复制整个数据库目录
使用 mysqlhotcopy 工具快速备份

使用mysqldump命令备份

直接复制整个数据库目录

MySQL 有一种最简单的备份方法,就是将 MySQL 中的数据库文件直接复制出来。这
种方法最简单,速度也最快。
使用这种方法时,最好将服务器先停止,这样以保证复制期间数据库中的数据不发
生变化。
但实际情况可能不允许停止 MySQL 服务器,且,该方法对 InnoDB 存储引擎的表不适
用。对于 MyISAM 存储引擎的表,是可以的。

使用mysqlhotcopy工具快速备份

如果备份时不能停止 MySQL 服务器,可以采用 mysqlhotcopy 工具。 mysqlhotcopy 工具的
备份方式比 mysqldump 命令快。
Mysqlhotcopy 工作原理:
Mysqlhotcopy 是一个 Perl 脚本,主要在 Linux 操作系统下使用。它使用 LOCK TABLES,
FLUSH TABLES cp 进行快速备份。具体的:
首先,将需要备份的数据库加上一个读操作锁,
然后,用 FLUSH TABLES 将内存中的数据写回到硬盘上的数据库中,
最后,把需要备份的数据库文件复制到目标目录。

7数据恢复

使用 mysql 命令还原
直接复制到数据库目录

使用mysql命令还原

直接复制到数据库目录

通过这种方式备份的数据,可以直接复制到 MySQL 的数据库目录下。通过这种方式还原
时,必须保证两个 MySQL 数据库的主版本号是相同的。而且,这种方式对 MyISAM 类型
的表比较有效。对于 InnoDB 类型的表则不可用。因为 InnoDB 表的表空间不能直接复制。

8数据库迁移

数据库迁移就是指将数据库从一个系统移动到另一个系统上。数据库迁移的原因是多种
多样的。可能是因为升级了计算机,或者是部署开发的管理系统,或者升级了 MySQL
据库。甚至是换用其他的数据库。根据上述情况,可以将数据库迁移大致分为 3 类。这 3
类分别是在相同版本的 MySQL 数据库之间迁移、迁移到其他版本的 MySQL 数据库中和迁
移到其他类型的数据库中。本节将介绍数据库迁移的方法。

相同版本的MySQL数据库之间的迁移

相同版本的 MySQL 数据库之间的迁移就是在主版本号相同的 MySQL 数据库之间进行数据
库移动。这种迁移的方式最容易实现。

不同数据库之间的迁移

不同数据库之间迁移是指从其他类型的数据库迁移到 MySQL 数据库,或者从 MySQL 数据
库迁移到其他类型的数据库。

9表的导出和导入

SELECT ...INTO OUTFILE导出文本文件

MySQL 中,可以在命令行窗口( MySQL Commend Line Client )中使用 SELECT…INTO
OUTFILE语句将表的内容导出成一个文本文件。

mysqldump命令导出文本文件

mysqldump 命令可以备份数据库中的数据。但是,备份时是在备份文件中保存了 CREATE
语句和INSERT语句。

mysql命令导出文本文件

mysql 命令可以用来登录 MySQL 服务器,也可以用来还原备份文件。同时, mysql 命令也
可以导出文本文件。

LOAD DATA INFILE命令将文本文件导入到数据表

MySQL 中,可以通过命令 LOAD DATA INFILE 来实现将指定格式的文本文件导入到数据
表中。
注意:需要选择要导入的数据库,并建立数据表,再执行导入 .

mysqlimport命令导入文本文件

MySQL 中,如果只是恢复数据表中的数据,可以在 Windows 的命令提示符窗口中使用
mysqllimport命令来实现。

10 Python API

1安装

1. 首先,确保python已经安装,要求python在3.5以上,没有的,可以登录到
https://www.python.org/ 进行下载,如下图即安装成功:
C:\Users\17408>python
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
python-mysql安装
pip install mysqlclient
pip地址:
https://pypi.python.org/pypi/mysqlclient
windows无法安装时:
https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient
用pip install xxx.whl文件

2 查询

前面的代码实现了数据库的连接,但该代码需要优化。

实际项目中,需要多次进行查询操作,不可能每次查询都执行一次连接。
也就是连接,包括关闭,属于公用的,考虑封装为一个class
阅读代码: “ test_search_mysql_1.py ”,先学到get_one
import pymysql

pymysql.install_as_MySQLdb()

import MySQLdb

class MysqlSearch(object):

    def __init__(self):
        self.get_conn()

    def get_conn(self):
        try:
            self.conn = MySQLdb.connect(
                host='127.0.0.1',
                user='root',
                passwd='root',
                db='news',
                port=3306,
                charset='utf8'
            )
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def close_conn(self):
        try:
            if self.conn:
                # 关闭链接
                self.conn.close()
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def get_one(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor(中间人)
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))#元组
        # 拿到结果
        rest = cursor.fetchone()

        # 处理数据
        # 暂且执行
        print(rest)
        # 关闭cursor/连接
        cursor.close()
        self.close_conn()
        #return rest

    def get_more(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))
        # print(dir(cursor))
        # 拿到结果
        rest = [dict(zip([k[0] for k in cursor.description], row))
            for row in cursor.fetchall()]
        # 处理数据
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest


def main():
    obj = MysqlSearch()
    #obj.get_one()
    rest = obj.get_one()
    print(rest['title'])

    # rest = obj.get_more()
    # for item in rest:
    #     print(item)
    #     print('------')

    
if __name__ == '__main__':
    main()

显然,数据库中查出的数据是元组类型的。
但是我们希望能够通过结果访问某个字段,比如:
print(rest[‘title‘])(这种访问属于字典式访问),显然
title在get_one()结果中并没有
此时,需要通过cursor获取数据,比如id, title等
import pymysql

pymysql.install_as_MySQLdb()

import MySQLdb

class MysqlSearch(object):

    def __init__(self):
        self.get_conn()

    def get_conn(self):
        try:
            self.conn = MySQLdb.connect(
                host='127.0.0.1',
                user='root',
                passwd='root',
                db='news',
                port=3306,
                charset='utf8'
            )
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def close_conn(self):
        try:
            if self.conn:
                # 关闭链接
                self.conn.close()
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def get_one(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor(中间人)
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))#元组
        print(cursor.rowcount)
        print("************************************************")
        print(dir(cursor))
        print("************************************************")
        print(cursor.description)

        rest = cursor.fetchone()

        # 关闭cursor/连接
        cursor.close()
        self.close_conn()
        #return rest

    def get_more(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))
        # print(dir(cursor))
        # 拿到结果
        rest = [dict(zip([k[0] for k in cursor.description], row))
            for row in cursor.fetchall()]
        # 处理数据
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest

def main():
    obj = MysqlSearch()
    obj.get_one()
    # rest = obj.get_one()
    # print(rest['title'])

    # rest = obj.get_more()
    # for item in rest:
    #     print(item)
    #     print('------')

if __name__ == '__main__':
    main()
print(rest[‘title‘]),是字典, 因此,需要将id等信息进行关联.
#拿到结果
rest = dict(zip([k[0] for k in cursor.description],
cursor.fetchone()))
执行结果:
C:\Users\17408>python test_search_mysql_4.py
男子长得像"祁同伟"挨打 打人者:为何加害检察官

3获取多条数据

需要修改获取数据的代码为列表形式,并逐条取出
rest = [dict(zip([k[0] for k in cursor.description], row))
for row in cursor.fetchall()]
import pymysql

pymysql.install_as_MySQLdb()

import MySQLdb

class MysqlSearch(object):

    def __init__(self):
        self.get_conn()

    def get_conn(self):
        try:
            self.conn = MySQLdb.connect(
                host='127.0.0.1',
                user='root',
                passwd='root',
                db='news',
                port=3306,
                charset='utf8'
            )
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def close_conn(self):
        try:
            if self.conn:
                # 关闭链接
                self.conn.close()
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def get_one(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor(中间人)
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))#元组
        # 拿到结果
        rest = dict(zip([k[0] for k in cursor.description], cursor.fetchone()))
       
        # 处理数据
        
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest

    def get_more(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))
        
        # 拿到结果
        rest = [dict(zip([k[0] for k in cursor.description], row))
           for row in cursor.fetchall()]
        

        # 处理数据
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest
        
def main():
    obj = MysqlSearch()
    #obj.get_one()
    # rest = obj.get_one()
    # print(rest['title'])

    rest = obj.get_more()
    for item in rest:
        print(item)
        print('------')


if __name__ == '__main__':
    main()

我们还可以做得更多,比如分页
def get_more_by_page(self, page, page_size):
… …. …

新增数据到数据库

11 ORM SQLAlchemy

ORM Object Relational Mapping ,对象关系映射)让畏惧 SQL 的开发者在一定程度上得到了解救,他们可以通过ORM 绕过 SQL ORM就是把数据库的一个个table( ) 映射为编程语言里的 class (类)。Python是面向对象的,一切皆对象!但是我们的数据库是关系型的,为保证一致的使用习惯,通过ORM 将编程语言中的 对象模型和数据库的关系模型 建立映射关系。使用编程语言对数据库操作的时候,可直接使用编程语言的对象模型操作数据库,而不用写SQL 语句。 ORM把表映射成类,把行映射成实例,把字段映射为属性 ,在执行对象操作时,最终会把对象的操作转换为数据库原生语句。
通过 PyMySQL 操作 MySQL 数据库,用的是直接编写 SQL语句的方式,这种操作对于不熟悉SQL 语句的开发人员是一个比较大的挑战。接下来,我们学习一种更适合程序开发者通过代码操作数据库的框架---SQLAlchemy.
安装
pip install SQLAlchemy
测试
>>> import sqlalchemy
>>> sqlalchemy.__version__
'1.3.19'
>>>

常见数据类型

常见类型
Integer
Float
Boolean
ForeignKey
Date/DateTime
String
.。。。。。。。

1

接下来,需要将模型对应到数据库了,前提是: news_test 已经创建好了。
先引入 News
C:\Users\17408>python
Python 3.8.6 (tags/v3.8.6:db45529, Sep 23 2020, 15:52:53) [MSC v.1927 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from test_mysql_orm_1 import News
>>>
Base.metadata.create_all(engine)
然后建数据表, Create a Schema 下参考建表方法
>>> News.metadata.create_all(engine)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError : name 'engine' is not defined
>>> from test_mysql_orm_1 import engine
>>> News.metadata.create_all(engine)
>>>
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime, Boolean

engine = create_engine("mysql://root:root@localhost:3306/news_test")#此处的数据库为了便于区分,新建一个news_test
Base = declarative_base()

class News(Base):#继承基类
    ''' 新闻类型 '''
    __tablename__ = 'news'
    id = Column(Integer, primary_key=True)
    title = Column(String(200), nullable=False)
    content = Column(String(2000), nullable=False)
    types = Column(String(10), nullable=False)
    image = Column(String(300))
    author = Column(String(20))
    view_count = Column(Integer)
    created_at = Column(DateTime)
    is_valid = Column(Boolean)

2

#!/usr/bin/python
#coding=utf-8

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Column, Integer, String, DateTime, Boolean

engine = create_engine("mysql://root:@127.0.0.1:3308/news?charset=utf8")

Session = sessionmaker(bind=engine)

Base = declarative_base()


class News(Base):
    ''' 新闻类型 '''
    __tablename__ = 'news'
    id = Column(Integer, primary_key=True)
    title = Column(String(200), nullable=False)
    content = Column(String(2000), nullable=False)
    types = Column(String(10), nullable=False)
    image = Column(String(300))
    author = Column(String(20))
    view_count = Column(Integer)
    created_at = Column(DateTime)
    is_valid = Column(Boolean)


class MysqlOrmTest(object):

    def __init__(self):
        self.session = Session()

    def add_one(self):
        ''' 添加数据 '''
        new_obj = News(
            title='ORM标题',
            content='content',
            types="百家"
        )
        self.session.add(new_obj)
        self.session.commit()
        return new_obj

    def get_one(self):
        ''' 获取一条数据 '''
        return self.session.query(News).get(1)

    def get_more(self):
        ''' 获取多条数据 '''
        return self.session.query(News).filter_by(is_valid=1)

    def update_data(self):
        ''' 修改数据 '''
        obj = self.session.query(News).get(38)
        obj.is_valid = 0
        self.session.add(obj)
        self.session.commit()
        return obj

    def delete_data(self):
        ''' 删除数据 '''
        # 获取要删除的数据
        data = self.session.query(News).get(39)
        self.session.delete(data)
        self.session.commit()


def main():
    obj = MysqlOrmTest()
    # rest = obj.add_one()
    # print(dir(rest))
    # print(obj.get_one().title)

    # print(obj.get_more().count())
    # for row in obj.get_more():
    #     print(row.title)

    # print(obj.update_data())

    obj.delete_data()



if __name__ == '__main__':
    main()

3

import pymysql

pymysql.install_as_MySQLdb()

import MySQLdb

class MysqlSearch(object):

    def __init__(self):
        self.get_conn()

    def get_conn(self):
        try:
            self.conn = MySQLdb.connect(
                host='127.0.0.1',
                user='root',
                passwd='root',
                db='news',
                port=3306,
                charset='utf8'
            )
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def close_conn(self):
        try:
            if self.conn:
                # 关闭链接
                self.conn.close()
        except MySQLdb.Error as e:
            print('Error: %s' % e)

    def get_one(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor(中间人)
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))#元祖
        # 拿到结果
        rest = dict(zip([k[0] for k in cursor.description], cursor.fetchone()))
       
        # 处理数据
        
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest

    def get_more(self):
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC;'
        # 找到cursor
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', ))
        # print(dir(cursor))
        # 拿到结果
        rest = [dict(zip([k[0] for k in cursor.description], row))
            for row in cursor.fetchall()]
        # 处理数据
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest

    def get_more_by_page(self, page, page_size):
        ''' 分页查询数据 '''
        offset = (page - 1) * page_size
        # 准备SQL
        sql = 'SELECT * FROM `news` WHERE `types` = %s ORDER BY `created_at` DESC LIMIT %s, %s;'
        # 找到cursor
        cursor = self.conn.cursor()
        # 执行SQL
        cursor.execute(sql, ('百家', offset, page_size))
        # print(dir(cursor))
        # 拿到结果
        rest = [dict(zip([k[0] for k in cursor.description], row)) 
            for row in cursor.fetchall()]
        # 处理数据
        # 关闭cursor/链接
        cursor.close()
        self.close_conn()
        return rest

    
def main():
    obj = MysqlSearch()
    #obj.get_one()
    # rest = obj.get_one()
    # print(rest['title'])

    # rest = obj.get_more()
    # for item in rest:
    #     print(item)
    #     print('------')

    rest = obj.get_more_by_page(1, 3)
    for item in rest:
        print(item)
        print('------')

if __name__ == '__main__':
    main()

12 网易新闻实战

import pymysql

pymysql.install_as_MySQLdb()

from flask import Flask, render_template, flash, redirect, url_for, abort, request
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
import requests
import json
import re
import time
from random import choice
from requests.exceptions import RequestException
from fake_useragent import UserAgent
from sqlalchemy import text

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:1234567@localhost:3306/db_database08?charset=utf8mb4'
db = SQLAlchemy(app)
app.config["SECRET_KEY"] = 'd6f96a238e074f9dba7330d471951373'


class News(db.Model):
    __tablename__ = 'news'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.String(2000), nullable=False)
    types = db.Column(db.String(10), nullable=False)
    image = db.Column(db.String(300))
    author = db.Column(db.String(20))
    view_count = db.Column(db.Integer)
    created_at = db.Column(db.DateTime)
    is_valid = db.Column(db.Boolean)

    def __repr__(self):
        return '<News %r>' % self.title


def save_news_to_db():
    def fetch_news_data():
        url = 'https://3g.163.com/touch/reconstruct/article/list/BA10TA81wangning/0-20.html'
        try:
            response = requests.get(url)
            response.raise_for_status()
            json_data = response.text
            json_data = json_data[json_data.index('artiList(') + len('artiList('):-1]
            data = json.loads(json_data)
            articles = data.get('BA10TA81wangning', [])
            return articles
        except Exception as e:
            print(f"Error fetching news data: {e}")
            return []

    def clean_html_content(text):
        """ 清理掉 <a> 标签内容,保留标签内的文本 """
        text = re.sub(r'<a.*?>(.*?)</a>', r'\1', text, flags=re.DOTALL)
        # 删除 <strong> 标签及其内容
        text = re.sub('</strong>', '', text, flags=re.DOTALL)

        text = re.sub('<strong>', '', text, flags=re.DOTALL)

        # 删除 <figure> 标签及其内容
        text = re.sub(r'<figure.*?>.*?</figure>', '', text, flags=re.DOTALL)

        # 删除 <blockquote> 标签及其内容
        text = re.sub(r'<blockquote.*?>.*?</blockquote>', '', text, flags=re.DOTALL)
        return text

    def extract_content(text):
        clean_text = clean_html_content(text)
        title_pattern = r'<title>(.*?)</title>'
        title_match = re.search(title_pattern, clean_text, re.IGNORECASE)
        title = title_match.group(1) if title_match else "标题未找到"

        p_pattern = r'<p.*?>(.*?)</p>'
        p_matches = re.findall(p_pattern, clean_text, re.IGNORECASE | re.DOTALL)
        return title, p_matches

    def fetch_full_content(url):
        try:
            headers = {'User-Agent': UserAgent().random}
            response = requests.get(url, headers=headers)
            if response.status_code == 200:
                return response.text
            else:
                print(f"Failed to fetch content from {url}")
                return None
        except RequestException as e:
            print(f"Error fetching full content: {e}")
            return None

    # 获取新闻列表
    news_data = fetch_news_data()
    for news in news_data:
        article_url = news.get("url")
        full_content = ""
        if article_url:
            article_response = fetch_full_content(article_url)
            if article_response:
                # 提取标题和段落内容
                title, paragraphs = extract_content(article_response)
                full_content = f"标题: {title}\n" + "\n".join(paragraphs)
            else:
                print("无法获取文章的详细内容")

        new_obj = News(
            title=news.get('title'),
            content=news.get('digest', 'No content available') + '\n' + full_content,  # Store URL and full_content
            types=news.get('type', '娱乐'),
            image=news.get('imgsrc'),
            author=news.get('source', 'Unknown'),
            view_count=news.get('replyCount', 0),
            created_at=news.get('ptime', datetime.now()),
            is_valid=True
        )
        db.session.add(new_obj)
    db.session.execute(text("ALTER TABLE news AUTO_INCREMENT = 1;"))
    db.session.commit()


@app.route('/')
def index():
    news_list = News.query.all()
    return render_template('index.html', news_list=news_list)


@app.route('/cat/<name>/')
def cat(name):
    news_list = News.query.filter(News.types == name)
    return render_template('cat.html', name=name, news_list=news_list)


@app.route('/detail/<int:pk>/')
def detail(pk):
    new_obj = News.query.get(pk)
    return render_template('detail.html', new_obj=new_obj)


@app.route('/admin/', methods=['GET', 'POST'])
@app.route('/admin/<int:page>', methods=['GET', 'POST'])
def admin(page=1):
    if request.method == 'POST' and 'refresh' in request.form:
        save_news_to_db()
        flash("新闻已刷新")
        return redirect(url_for('admin', page=page))
    page_data = News.query.filter_by(is_valid=True).paginate(page=page, per_page=5)
    return render_template('admin/index.html', page_data=page_data)


@app.route('/admin/add/', methods=('GET', 'POST'))
def add():
    form = NewsForm()
    if form.validate_on_submit():
        new_obj = News(
            title=form.title.data,
            content=form.content.data,
            image=form.image.data,
            types=form.types.data,
            created_at=datetime.now(),
        )
        db.session.add(new_obj)
        db.session.commit()
        flash("新增成功")
        return redirect(url_for('admin'))
    return render_template("admin/add.html", form=form)


@app.route('/admin/update/<int:pk>/', methods=('GET', 'POST'))
def update(pk):
    obj = News.query.get(pk)
    if obj is None:
        abort(404)
    form = NewsForm(obj=obj)
    if form.validate_on_submit():
        obj.title = form.title.data
        obj.content = form.content.data
        obj.news_type = form.types.data
        db.session.add(obj)
        db.session.commit()
        flash("修改成功")
        return redirect(url_for('admin'))
    return render_template("admin/update.html", form=form)


@app.route('/admin/delete/<int:pk>/', methods=['GET', 'POST'])
def delete(pk):
    """ 异步ajax删除 逻辑删除 """
    new_obj = News.query.get(pk)
    if not new_obj:
        return 'no'
    new_obj.is_valid = False
    db.session.add(new_obj)
    db.session.commit()

    # 重排ID顺序
    db.session.execute("SET @new_id = 0;")
    db.session.execute("UPDATE news SET id = (@new_id := @new_id + 1) ORDER BY id;")
    db.session.commit()
    return 'yes'


if __name__ == '__main__':
    app.run(debug=True)

13 MongoDB基础

MongoDB简介、基本概念

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编

写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,
是非关系数据库 当中功能最丰富,最像关系数据库的。
MongoDB 的特色及应用:详见 https://www.runoob.com/mongodb/mongodb-intro.html
MongoDB 中文手册 | 官方文档中文版: https://docs.mongoing.com/
MongoDB 英文手册 | 官方文档英文版: https://docs.mongodb.com/manual/
MongoDB 教程 https://www.runoob.com/mongodb/mongodb-tutorial.html
数字校园有一座后山,名叫 Mongo 山。 Mongo 山上长满了各种植物,
各种植物以非常不规则的方式生长在山上各个地方。没有一种植物以
一块一块的方式生长,也没有成排或成列生长的,都是以一种非常自
然的个体对象存在。同学们上山玩耍时,可以将某棵野草拔起,也可
以将某棵树木做一番修剪,还可以将某类植物全部铲除。这些操作都
不会对其他个体对象或其他植物产生影响。
MongoDB 中数据的存放如 Mongo 山上的植物,没有排或列的概念,只
有集合、文档等概念。 MongoDB 中的数据库如一座 Mongo 山,集合如
Mongo 山上的各种植物,可以有多个,文档如 Mongo 山上的个体对象,
有各种属性。删除文档犹如拔除某棵野草,修改文档犹如修剪某棵树
木,删除集合犹如铲除某类植物等。

MongoDB基本操作

1. 新增数据(Create)

> stu = { name: 'Jhon', age: 21, sex: "male" } > db.students.insert(stu)

这会将一个包含姓名、年龄和性别的文档插入到 students 集合。

你也展示了如何插入新的数据:

> db.students.insert({ name: 'Amy' })
> show dbs;
admin 0.000GB---指所用空间
config 0.000GB
local 0.000GB
mongodb_mysql 0.000GB
> use students---无需创建,使用即创建
switched to db students
> db---查看当前在用数据库
students
> stu={
... name:'Jhon',
... age:21,
... sex:"male"
... }
{ "name" : "Jhon", "age" : 21, "sex" : "male" }
> db.students.insert(stu)---将stu对象加入数据库
WriteResult({ "nInserted" : 1 })
>

2. 查询数据(Read)

你使用了以下命令来查看 students 集合中的所有文档:

> db.students.find()
> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "Jhon", "age" : 21, "sex" : 
"male" }
> db.students.insert({name:'Amy'})
WriteResult({ "nInserted" : 1 })
> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "Jhon", "age" : 21, "sex" : 
"male" }
{ "_id" : ObjectId("5fc5e049b306bbfe8da27369"), "name" : "Amy" }
> db.students.findOne()
{
 "_id" : ObjectId("5fc5deecb306bbfe8da27368"),
 "name" : "Jhon",
 "age" : 21,
 "sex" : "male"
}

find() 方法用于查询集合中的所有数据。

你也使用了 findOne() 方法,它返回集合中的第一个文档:

> db.students.findOne()

3. 修改数据(Update)

修改数据时,你使用了 update() 方法来更新文档中的某些字段:

> db.students.update({ name: 'Jhon' }, { name: 'JohnC' })

这将 nameJhon 的文档的姓名修改为 JohnC

你还演示了如何用完整的文档进行更新:

> db.students.update({ name: 'Amy2' }, stu_update2)

这个命令将找到 nameAmy2 的文档,并用 stu_update2 文档替换它。

> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "Jhon", "age" : 21, "sex" : 
"male" }
{ "_id" : ObjectId("5fc5e049b306bbfe8da27369"), "name" : "Amy" }
{ "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy2", "age" : 16, "sex" : 
"male" }
> db.students.update({name:'Jhon'},{name:'JohnC'})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "JohnC" }
{ "_id" : ObjectId("5fc5e049b306bbfe8da27369"), "name" : "Amy" }
{ "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy2", "age" : 16, "sex" : 
"male" }
> stu_update2 = { "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy2", "age" : 16, 
"sex" : "male" }
{
 "_id" : ObjectId("5fc5e11db306bbfe8da2736a"),
 "name" : "Amy2",
 "age" : 16,
 "sex" : "male"
}
> stu_update2.name = "Amy3"
Amy3
> db.students.update({name:'Amy2'},stu_update2)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "JohnC" }
{ "_id" : ObjectId("5fc5e049b306bbfe8da27369"), "name" : "Amy" }
{ "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy3", "age" : 16, "sex" : 
"male" }
>

4. 删除数据(Delete)

删除数据时,你使用了 remove() 方法:

> db.students.remove({ name: 'Amy' })

这会删除 nameAmy 的文档。

如果删除所有文档,可以使用如下命令:

> db.students.remove({})

这会清空 students 集合中的所有数据。

> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "JohnC" }
{ "_id" : ObjectId("5fc5e049b306bbfe8da27369"), "name" : "Amy" }
{ "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy3", "age" : 16, "sex" : 
"male" }
> db.students.remove({name:'Amy'})
WriteResult({ "nRemoved" : 1 })
> db.students.find()
{ "_id" : ObjectId("5fc5deecb306bbfe8da27368"), "name" : "JohnC" }
{ "_id" : ObjectId("5fc5e11db306bbfe8da2736a"), "name" : "Amy3", "age" : 16, "sex" : 
"male" }
> db.students.remove({ })
WriteResult({ "nRemoved" : 2 })
> db.students.find()

总结:

  • Create(新增)insert() 方法。
  • Read(查询)find() 和 findOne() 方法。
  • Update(修改)update() 方法。
  • Delete(删除)remove() 方法。

以下文档可以存储在 MongoDB runoob 数据库 的 col 集合中:
> db . col . insert ({ title : 'MongoDB 教程’ ,
description : 'MongoDB 是一个 Nosql 数据库’ ,
by : ' 菜鸟教程’ ,
url : 'http://www.runoob.com ,
tags : [ 'mongodb' , 'database' , 'NoSQL ],
likes : 100
})
以上实例中 col 是我们的集合名,如果该集合不在该数据库中,
MongoDB 会自动创建该集合并插入文档。
查看已插入文档:
>db . col . find ()
> { "_id" : ObjectId ( "56064886ade2f21f36b03134" ), "title" : "MongoDB 教程 " , "description" :
"MongoDB 是一个 Nosql 数据库 " , "by" : " 菜鸟教程 " , "url" : "http://www.runoob.com" , "tags" : [
"mongodb" , "database" , "NoSQL" ], "likes" : 100 } 我们也可以将数据定义为一个变量,如下所示:
>document =({ title : 'MongoDB 教程’ ,
description : 'MongoDB 是一个 Nosql 数据库’ ,
by : ' 菜鸟教程’ ,
url : 'http://www.runoob.com ,
tags : [ 'mongodb' , 'database' , 'NoSQL ],
likes : 100
});
执行插入操作:
>db . col . insert ( document )
WriteResult ({ "nInserted" : 1 })
>
插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id
字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新
_id 的数据。 查询文档
MongoDB 查询文档使用 find() 方法。
find() 方法以非结构化的方式来显示所有文档。
语法
MongoDB 查询数据的语法格式如下:
db . collection . find ( query , projection )
query :可选,使用查询操作符指定查询条件
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需
省略该参数即可(默认省略)。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
> db . col . find (). pretty ()
pretty() 方法以格式化的方式来显示所有文档。
实例
>db . col . find (). pretty ()
{
"_id" : ObjectId ( "56063f17ade2f21f36b03133" ),
"title" : "MongoDB 教程 " ,
"description" : "MongoDB 是一个 Nosql 数据库 " ,
"by" : " 菜鸟教程 " ,
"url" : "http://www.runoob.com" ,
"tags" : [ "mongodb" , "database" , "NoSQL" ],
"likes" : 100
}
除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个
文档。

在 MongoDB 中,AND 条件用于匹配同时满足多个查询条件的文档。MongoDB 默认支持 AND 条件,当你在 find() 查询中同时指定多个条件时,MongoDB 会自动将它们视为 AND 条件。

示例:使用 AND 条件查询

假设我们有一个 students 集合,包含以下文档:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 2, "name": "Amy", "age": 22, "sex": "female" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" } { "_id": 4, "name": "Emma", "age": 22, "sex": "female" }

我们希望查询年龄为 21 且性别为男性的学生,这就需要使用 AND 条件:

db.students.find({ age: 21, sex: "male" })

这将返回所有同时满足这两个条件的文档(即,年龄为 21 且性别为 "male")。

解释:

  • 在 find() 方法中,多个查询条件(如 { age: 21, sex: "male" })会自动被视为 AND 条件。
  • 上述查询会返回:
{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" }

这两个文档都符合 age: 21sex: "male" 的条件。

使用 $and 显式指定 AND 条件

你也可以使用 $and 操作符来显式指定多个条件,特别是在需要组合更复杂的查询时。$and 操作符接受一个数组,数组中的每个元素是一个查询条件对象。

例如,如果我们想查询年龄为 21 且性别为男性的学生,可以显式使用 $and 操作符:

db.students.find({ $and: [ { age: 21 }, { sex: "male" } ] })

这条查询与上面那个默认 AND 查询的效果相同,都会返回:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" }

使用多个 AND 条件

如果你要查询多个条件,可以继续在 $and 数组中添加更多的查询对象。例如,查询年龄为 21 且性别为男性,且名字包含 "M" 的学生:

db.students.find({ $and: [ { age: 21 }, { sex: "male" }, { name: /M/ } ] })

这个查询会返回:

{ "_id": 3, "name": "Mike", "age": 21, "sex": "male" }
  • 默认情况下,在 MongoDB 的 find() 查询中使用多个条件时,它们会自动作为 AND 条件处理。
  • 如果需要更复杂的 AND 查询,可以使用 $and 操作符来显式指定多个条件。
  • $and 可以帮助你组合任意多个查询条件,支持灵活的查询逻辑。

在 MongoDB 中,OR 条件用于匹配至少满足其中一个查询条件的文档。与 AND 条件类似,OR 条件可以通过使用 $or 操作符显式指定。MongoDB 默认并不自动处理 OR 条件,需要使用 $or 来明确指定多个查询条件中的任意一个。

示例:使用 OR 条件查询

假设我们有一个 students 集合,包含以下文档:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 2, "name": "Amy", "age": 22, "sex": "female" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" } { "_id": 4, "name": "Emma", "age": 22, "sex": "female" }

假设我们想查询年龄为 21 或性别为女性的学生,这就需要使用 OR 条件。

1. 使用 $or 显式指定 OR 条件

你可以使用 $or 操作符,后跟一个包含多个查询条件的数组。例如,查询年龄为 21 或性别为女性的学生:

db.students.find({ $or: [ { age: 21 }, { sex: "female" } ] })

查询结果

这条查询会返回以下文档,符合 age: 21sex: "female" 的学生:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 2, "name": "Amy", "age": 22, "sex": "female" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" } { "_id": 4, "name": "Emma", "age": 22, "sex": "female" }

示例:AND 和 OR 联合使用

假设我们有一个 students 集合,包含以下文档:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" } { "_id": 2, "name": "Amy", "age": 22, "sex": "female" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" } { "_id": 4, "name": "Emma", "age": 22, "sex": "female" }

1. 使用 $and 和 $or 结合查询

假设我们想查询:

  • 年龄为 21 或 22,
  • 且性别为 "female" 或名字包含字母 "M"。

为了实现这个查询,我们需要用到 $and$or 操作符,组合多个条件。查询可以写作:

db.students.find({ $and: [ { $or: [ { age: 21 }, { age: 22 } ] }, // 年龄为 21 或 22 { $or: [ { sex: "female" }, { name: /M/ } ] } // 性别为 female 或名字包含 M ] })

查询结果

这条查询会返回符合以下两个条件的文档:

  1. 年龄为 21 或 22
  2. 性别为 "female" 或名字中包含字母 "M"。

查询结果:

{ "_id": 2, "name": "Amy", "age": 22, "sex": "female" } { "_id": 3, "name": "Mike", "age": 21, "sex": "male" } { "_id": 4, "name": "Emma", "age": 22, "sex": "female" }

2. 复杂的联合查询

假设我们想查询以下情况:

  • 年龄为 21 或 22,
  • 并且名字包含字母 "J",
  • 或者性别为 "male" 且年龄大于 21。

查询可以这样写:

db.students.find({ $and: [ { $or: [ { age: 21 }, { age: 22 } ] }, // 年龄为 21 或 22 { name: /J/ }, // 名字包含 "J" { $or: [ { sex: "male" }, // 性别为 "male" { age: { $gt: 21 } } // 年龄大于 21 ]} ] })

查询结果

这条查询会返回符合以下条件的文档:

  1. 年龄为 21 或 22
  2. 名字包含字母 "J"
  3. 或者,性别为 "male" 且年龄大于 21

查询结果:

{ "_id": 1, "name": "Jhon", "age": 21, "sex": "male" }

在 MongoDB 中,条件操作符用于比较表达式中的值,以便从集合中筛选出符合条件的数据。常用的条件操作符包括 $gt$lt$gte$lte,它们分别用于进行大于、小于、大于等于和小于等于的比较。

以下是这些条件操作符的具体说明和使用方法:

1. $gt(大于)

  • 说明:用于查询大于指定值的文档。
  • 语法{ field: { $gt: value } }
  • 示例:查询 age 大于 25 的文档:
db.users.find({ age: { $gt: 25 } })

2. $lt(小于)

  • 说明:用于查询小于指定值的文档。
  • 语法{ field: { $lt: value } }
  • 示例:查询 age 小于 30 的文档:
db.users.find({ age: { $lt: 30 } })

3. $gte(大于等于)

  • 说明:用于查询大于或等于指定值的文档。
  • 语法{ field: { $gte: value } }
  • 示例:查询 age 大于或等于 18 的文档:
db.users.find({ age: { $gte: 18 } })

4. $lte(小于等于)

  • 说明:用于查询小于或等于指定值的文档。
  • 语法{ field: { $lte: value } }
  • 示例:查询 age 小于或等于 50 的文档:
db.users.find({ age: { $lte: 50 } })

复合查询

这些条件操作符不仅可以单独使用,还可以与其他查询条件组合使用。例如,结合 $gt$lt 操作符,查询年龄在 18 到 30 之间的文档:

db.users.find({ age: { $gt: 18, $lt: 30 } })

此查询将返回 age 大于 18 且小于 30 的所有文档。

示例:查询年龄在 18 到 50 之间的男性用户

假设 users 集合包含如下文档:

{ "_id": 1, "name": "John", "age": 25, "sex": "male" } { "_id": 2, "name": "Alice", "age": 22, "sex": "female" } { "_id": 3, "name": "Bob", "age": 30, "sex": "male" } { "_id": 4, "name": "Charlie", "age": 35, "sex": "male" } { "_id": 5, "name": "David", "age": 60, "sex": "male" }

查询年龄在 18 到 50 之间的男性用户:

db.users.find({ age: { $gte: 18, $lte: 50 }, sex: "male" })

查询结果:

{ "_id": 1, "name": "John", "age": 25, "sex": "male" } { "_id": 3, "name": "Bob", "age": 30, "sex": "male" } { "_id": 4, "name": "Charlie", "age": 35, "sex": "male" }
  • $gt:大于指定值。
  • $lt:小于指定值。
  • $gte:大于或等于指定值。
  • $lte:小于或等于指定值。

这些条件操作符是 MongoDB 查询中非常重要的部分,它们使得你能够执行更加灵活和精确的数据筛选。在实际应用中,可以通过将这些操作符与其他操作符(如 $and$or 等)组合,构建复杂的查询条件。

1. MongoDB $type 操作符

$type 操作符用于查询指定字段的 BSON 数据类型。

语法:
{ field: { $type: <BSON_type> } }
  • 常见的 BSON 类型
    • 1: Double
    • 2: String
    • 3: Object
    • 4: Array
    • 5: Binary data
    • 8: Boolean
    • 9: Date
    • 10: Null
    • 16: Integer
    • 18: Undefined
示例:

查询所有 age 字段是整数类型的文档:

db.users.find({ age: { $type: 16 } })

查询所有 data 字段是数组类型的文档:

db.users.find({ data: { $type: 4 } })

2. MongoDB limit() 和 skip() 方法

  • limit():限制查询结果的数量。
  • skip():跳过查询结果的前 N 个文档。
语法:
  • limit()db.collection.find().limit(n)
  • skip()db.collection.find().skip(n)
示例:
  • 查询 users 集合中的前 5 个文档:
db.users.find().limit(5)
  • 查询 users 集合中的跳过前 3 个文档,获取接下来的 5 个文档:
db.users.find().skip(3).limit(5)

3. MongoDB sort() 方法

sort() 方法用于排序查询结果,可以按照升序(1)或降序(-1)进行排序。

语法:
db.collection.find().sort({ field: 1 }) // 升序 db.collection.find().sort({ field: -1 }) // 降序
示例:
  • 按 age 字段升序排序:
db.users.find().sort({ age: 1 })
  • 按 age 字段降序排序:
db.users.find().sort({ age: -1 })
  • 按多个字段排序:先按 age 降序,再按 name 升序排序:
db.users.find().sort({ age: -1, name: 1 })

4. MongoDB createIndex() 方法

createIndex() 方法用于为集合创建索引,优化查询性能。

语法:
db.collection.createIndex({ field: 1 }) // 升序索引 db.collection.createIndex({ field: -1 }) // 降序索引
示例:
  • 为 users 集合的 age 字段创建升序索引:
db.users.createIndex({ age: 1 })
  • 为 users 集合的 name 字段创建降序索引:
db.users.createIndex({ name: -1 })
  • 为 users 集合的 name 和 age 字段创建复合索引:
db.users.createIndex({ name: 1, age: -1 })

5. MongoDB aggregate() 方法

aggregate() 方法用于进行聚合操作,通过多个管道操作符对文档进行处理,如过滤、分组、排序等。

语法:
db.collection.aggregate([{ $stage: { ... } }])

常见的聚合阶段:

  • $match: 用于过滤文档,类似于 find() 查询。
  • $group: 用于分组操作,通常与聚合函数一起使用。
  • $sort: 用于排序。
  • $project: 用于指定输出字段。
示例:
  • 查询 users 集合中所有 age 大于 20 的用户,并按 age 降序排序:
db.users.aggregate([ { $match: { age: { $gt: 20 } } }, { $sort: { age: -1 } } ])
  • 分组统计每个 age 的用户数量:
db.users.aggregate([ { $group: { _id: "$age", count: { $sum: 1 } } } ])

6. MongoDB createCollection() 方法

createCollection() 方法用于显式地创建一个集合。通常在 MongoDB 中,插入数据时会自动创建集合,但有时也需要手动创建集合并定义集合的一些选项,如索引、数据存储等。

语法:
db.createCollection(name, options)
  • name: 集合的名称。
  • options: 可选参数,如 capped(是否为固定集合),size(集合的最大字节大小)。
示例:
  • 创建一个名为 users 的集合,并设置为固定大小:
db.createCollection("users", { capped: true, size: 5242880 })

7. MongoDB drop() 方法

drop() 方法用于删除集合或索引。

语法:
  • 删除集合:
db.collection.drop()
  • 删除索引:
db.collection.dropIndex("index_name")
示例:
  • 删除 users 集合:
db.users.drop()
  • 删除 age 字段的索引:
db.users.dropIndex("age_1")

总结:

  • $type:用于查询字段的 BSON 数据类型。
  • limit():限制查询结果的数量。
  • skip():跳过查询结果的前 N 个文档。
  • sort():对查询结果进行排序。
  • createIndex():为集合创建索引,提高查询性能。
  • aggregate():执行聚合操作,对文档进行复杂的处理和分析。
  • createCollection():手动创建集合,并可以设置集合的一些选项。
  • drop():删除集合或索引。

14 Python操作MongoDB

安装
pip install pymongo
查看安装
pip show pymongo

连接数据库
方式一:简写
client=MongoClient()
方式二:指定端口和地址
client=MongoClient(‘localhost’,27017)
方式三:使用 URI( 统一资源定位器,与 URL 不同 )
client=MongoClient(‘mongodb://localhost:27017/’)
from pymongo import MongoClient

class TestMongo(object):

    def __init__(self):
        self.client = MongoClient()
        self.db = self.client['students']


    def add_one(self):
        ''' 新增数据 '''
        post = {
            "name" : "张三",
		    "age" : 17,
		    "sex" : "male",
		    "grade" : 98.0,
		    "address" : "--"
        }
        return self.db.students.insert_one(post)


def main():
    obj = TestMongo()
    rest = obj.add_one()
    print(rest.inserted_id)

if __name__ == '__main__':
    main()
from datetime import datetime
from pymongo import MongoClient
from bson.objectid import ObjectId
from mongoengine import connect, Document, EmbeddedDocument, \
    StringField, IntField, FloatField, DateTimeField, ListField, \
    EmbeddedDocumentField


connect('test')
# connect('students', host='192.168.1.35', port=27017)
#connect('test', host='mongodb://localhost/students')

class Grade(EmbeddedDocument):
    ''' 学生的成绩 '''
    name = StringField(required=True)
    score = FloatField(required=True)


SEX_CHOICES = (
        ('female', '女'),
        ('male', '男')
    )

class Student(Document):
    ''' 学生模型 '''
    name = StringField(required=True, max_lenght=32)
    age = IntField(required=True)
    sex = StringField(required=True, choices=SEX_CHOICES)
    grade = FloatField()
    created_at = DateTimeField(default=datetime.now())
    grades = ListField(EmbeddedDocumentField(Grade))
    address = StringField()
    school = StringField()

    meta = {
        'collection': 'students'
    }


class TestMongoEngine(object):

    def add_one(self):
        ''' 添加一条数据到数据库 '''
        yuwen = Grade(
            name='语文',
            score=95
            )
        english = Grade(
            name='英语',
            score=89)
        stu_obj = Student(
            name='张三',
            age=21,
            sex='male',
            grades=[yuwen, english]
        )
        # stu_obj.test = 'OK'
        stu_obj.save()
        return stu_obj

    def get_one(self):
        ''' 查询一条数据 '''
        return Student.objects.first()

    def get_more(self):
        ''' 查询多条数据 '''
        # return Student.objects
        return Student.objects.all()
        #return Student.objects[:5]
        #return Student.objects().order_by('grade')

    def get_one_from_oid(self, oid):
        ''' 查询指定ID的数据 '''
        return Student.objects.filter(id=oid).first()

    def update(self):
        ''' 修改数据 '''
        # 修改一条数据
        # rest = Student.objects.filter(sex='male').update_one(inc__age=1)
        # return rest
        # 修改多条数据
        rest = Student.objects.filter(sex='male').update(inc__age=1)
        return rest

    def delete(self):
        ''' 删除数据 '''
        # 删除一条数据
        rest = Student.objects.filter(sex='male').first().delete()
        # 删除多条数据
        rest = Student.objects.filter(sex='male').delete()
        return rest

def main():
    obj = TestMongoEngine()
    # rest = obj.add_one()
    # print(rest.id)

    # rest = obj.get_one()
    # print(rest.id)

    rest = obj.get_more()
    print(type(rest))
    for item in rest:
        print(item.name)

    # rest = obj.get_one_from_oid('593bb8e7fa3ebd091078d40e')
    # print(rest.name)

    # rest = obj.update()
    # print(rest)

    # rest = obj.delete()
    # print(rest)

if __name__ == '__main__':
    main()
from datetime import datetime
from mongoengine import *


connect('students')
# connect('students', host='192.168.1.35', port=27017)
#connect('test', host='mongodb://localhost/students')


class Grade(EmbeddedDocument):
    """学生成绩"""
    name = StringField(required=True)
    score = FloatField(required=True)

SEX_CHOICES=(
        ('female','女'),
        ('male','男')
    )

class Student(Document):
    """学生模型"""
    name = StringField(required=True,max_length=32)
    age = IntField(required=True)
    sex = StringField(required=True,choices=SEX_CHOICES)
    grade = FloatField()
    created_at = DateTimeField(default=datetime.now())
    grades = ListField(EmbeddedDocumentField(Grade))
    address = StringField()
    school = StringField()

    meta = {
        'collection':'students'
    }

    def __str__(self):
        # 创建一个包含学生信息的字符串
        grades_str = ', '.join([f"{grade.name}: {grade.score}" for grade in self.grades])
        return (f"Student Name: {self.name}, Age: {self.age}, Sex: {self.sex}, "
                f"Grade: {self.grade}, Created At: {self.created_at}, "
                f"Address: {self.address}, School: {self.school}, "
                f"Grades: [{grades_str}]")

class TestMongoEngine(object):
    def add_one(self):
        """新增数据"""
        yuwen = Grade(
            name='语文',
            score=95
        )
        english = Grade(
            name='英语',
            score=89
        )
        stu_obj = Student(
            name='张三',
            age=21,
            sex='male',
            grades=[yuwen,english]
        )
        # stu_obj.test = 'OK'
        stu_obj.save()
        return stu_obj

    def get_one(self):
        """查询一条数据"""
        return Student.objects.first()

    def get_more(self):
        """查询多条数据"""
        return Student.objects.all()

    def get_one_from_oid(self,oid):
        """查询指定ID的数据"""
        return Student.objects.filter(id=oid).first()

    def update(self):
        """修改数据"""
        # 修改一条数据
        rest = Student.objects.filter(sex='male').update_one(inc__age=1)
        return rest
        # # 修改多个数据
        # rest = Student.objects.filter(sex='male').update(inc__age=1)
        # return rest

    def delete(self):
        """删除数据"""
        # 删除一条数据
        rest = Student.objects.filter(sex='male').first().delete()
        # 删除多条数据
        # rest = Student.objects.filter(sex='male').delete()
        return rest


def main():
    obj = TestMongoEngine()
    # rest = obj.add_one()
    # print(rest.id)

    # rest = obj.get_one()
    # print(rest.id)

    # rest = obj.get_more()
    # print(type(rest))
    # for item in rest:
    #     print(item.name)

    rest = obj.get_one_from_oid('67469abc0c7193368d06eaf6')
    print(rest)

    # rest = obj.update()
    # print(rest)

    # rest = obj.delete()
    # print(rest)


if __name__ == '__main__':
    main()

15 MongoDB网易新闻实战

from datetime import *
from flask import Flask, render_template, redirect, flash, url_for
from datetime import datetime
from flask_mongoengine import MongoEngine
from forms import NewsForm_mongo

app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {'db' : 'mongo_news','host':'127.0.0.1','port':27017}
db = MongoEngine(app)

app.config['SECRET_KEY'] = 'this is a mongodb key'

NEWS_TYPE = (
	('推荐','推荐'),
	('百家','百家'),
	('本地','本地'),
	('图片','图片'))

class News(db.Document):
    """ 新闻模型 """
    title = db.StringField(required=True, max_lenght=64)
    img_url = db.StringField(required=True)
    content = db.StringField(required=True)
    is_valid = db.BooleanField(default=True)
    news_type = db.StringField(required=True, choices=NEWS_TYPE)
    created_at = db.DateTimeField(default=datetime.now())
    updated_at = db.DateTimeField(default=datetime.now())

    meta = {'collection':'news',
    'ordering':['-created_at']
	}

    # def __repr__(self):
    #    return '<News %r>' % self.title

def gettime():
    time = datetime.now().strftime('%Y-%m-%d  %H:%M:%S')
    return time

@app.route('/')
def index():
    """ 新闻首页 """
    news_list = News.objects.all()
    return render_template("index.html",news_list = news_list,var=gettime())



@app.route('/cat/<name>/', methods=['GET', 'POST'])
def cat(name):
    ''' 栏目 '''
    news_list = News.objects.filter(is_valid=True, news_type=name).all()
    return render_template('cat.html', news_list=news_list,var=gettime())


@app.route('/detail/<pk>/', methods=['GET', 'POST'])
def detail(pk):
    ''' 新闻详情页 '''
    obj = News.objects.filter(pk=pk).first_or_404()
    return render_template('detail.html', new_obj=obj,var=gettime())

################################

@app.route('/admin/', methods=['GET', 'POST'])
@app.route('/admin/<page>/', methods=['GET', 'POST'])
def admin(page=None):
    ''' 后台首页 '''
    # 如果page参数没有传就默认显示首页
    if page == None:
        page = 1
    page_data = News.objects.paginate(page=int(page), per_page=5)
    return render_template('admin/index.html', page_data=page_data, page=int(page))


@app.route('/admin/add/', methods=['GET', 'POST'])
def add():
    ''' 添加新闻 '''
    form = NewsForm_mongo()
    if form.validate_on_submit:
        # 获取数据
        new_obj = News(
            title=form.title.data,
            img_url=form.img_url.data,
            content=form.content.data,
            news_type=form.news_type.data
        )

        new_obj.save()
        flash('新闻添加成功')
        return redirect(url_for('admin'))
    return render_template('admin/add.html', form=form)


@app.route('/admin/delete/<pk>/', methods=['GET', 'POST'])
def delete(pk):
    ''' 删除新闻 '''
    new_obj = News.objects.filter(pk=pk).first()
    print(new_obj.title)
    if not new_obj:
        return 'no'
    # 逻辑删除
    new_obj.is_valid = False
    new_obj.save()
    return 'yes'

    # 物理删除
    # new_obj.delete()
    # return 'yes'


@app.route('/admin/update/<pk>/', methods=['POST', 'GET'])
def update(pk):
    ''' 修改新闻 '''
    new_obj = News.objects.get_or_404(pk=pk)
    print(new_obj.title)
    form = NewsForm_mongo(obj=new_obj)
    if form.validate_on_submit():
        new_obj.title = form.title.data
        new_obj.content = form.content.data
        new_obj.news_type = form.news_type.data
        new_obj.img_url = form.img_url.data

        new_obj.save()
        flash('新闻修改成功')
        return redirect(url_for('admin'))
    return render_template('admin/update.html', form=form)

if __name__ == '__main__':
    app.run(debug=True)


# from flask_pymongo import PyMongo
# from flask import Flask
#
# app = Flask(__name__)
# app.config["MONGO_URI"] = "mongodb://127.0.0.1:27017/mongo_news"
# mongo = PyMongo(app)
#
# def insert_data():
#     mongo.db.news.insert_many(  # 修正大小写
#         [
#             {
#                 "title": "朝鲜特种部队视频公布 展示士兵身体素质与意志",
#                 "img_url": "/static/img/news/01.png",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "推荐"
#             },
#             {
#                 "title": "男子长得像\"祁同伟\"挨打 打人者:为何加害检察官",
#                 "img_url": "/static/img/news/02.png",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "百家"
#             },
#             {
#                 "title": "导弹来袭怎么办?日本政府呼吁国民躲入地下通道",
#                 "img_url": "/static/img/news/03.png",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "本地"
#             },
#             {
#                 "title": "美媒:朝在建能发射3发以上导弹的3000吨级新潜艇",
#                 "img_url": "/static/img/news/04.png",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "推荐"
#             },
#             {
#                 "title": "证监会:前发审委员冯小树违法买卖股票被罚4.99亿",
#                 "img_url": "/static/img/news/08.png",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "百家"
#             },
#             {
#                 "title": "外交部回应安倍参拜靖国神社:同军国主义划清界限",
#                 "img_url": "/static/img/news/new1.jpg",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "推荐"
#             },
#             {
#                 "title": "外交部回应安倍参拜靖国神社:同军国主义划清界限",
#                 "img_url": "/static/img/news/new1.jpg",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "百家"
#             },
#             {
#                 "title": "\"萨德\"供地违法?韩民众联名起诉要求撤回供地",
#                 "img_url": "/static/img/news/new1.jpg",
#                 "content": "新闻内容",
#                 "is_valid": True,
#                 "news_type": "百家"
#             }
#         ]
#     )
#     print("Data inserted successfully!")
#
# if __name__ == '__main__':
#     insert_data()  # 运行插入数据函数

16

17

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值