表的增删查改,即CRUD:Create(创建),Retrieve(读取),Update(更新),Delete(删除).
Create
语法:
sql
INSERT [INTO] table_name
[(column [, column] ...)]
VALUES (value_list) [, (value_list)] ...
value_list: value, [, value] ...
先创建一个表用于测试插入:
sql
CREATE TABLE students (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
sn INT NOT NULL UNIQUE COMMENT '学号',
name VARCHAR(20) NOT NULL,
qq VARCHAR(20)
);
全列插入
默认插入语法就是全列插入:
sql
mysql> insert into students values(1,23101,'刘玄德',8888);
Query OK, 1 row affected (0.01 sec)
mysql> insert students values(2,23102,'关云长',null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
+----+-------+-----------+------+
2 rows in set (0.00 sec)
可以看到我们可以省略into。
多行插入
我们可以,分隔来进行多行插入:
sql
mysql> insert into students values(3,23103,'张翼德',null),(4,23104,'曹孟德',null);
Query OK, 2 rows affected (0.01 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
+----+-------+-----------+------+
4 rows in set (0.00 sec)
指定列插入
此外,我们还能只插入指定列而非全列插入:

插入否则更新
由于 主键 或者 唯一键 对应的值已经存在而导致插入失败.
- 主键冲突:
sql
mysql> insert into students values(3,23106,'孙悟空',null);
ERROR 1062 (23000): Duplicate entry '3' for key 'students.PRIMARY'
- 唯一键冲突:
sql
mysql> insert into students values(6,23103,'猪悟能',null);
ERROR 1062 (23000): Duplicate entry '23103' for key 'students.sn'
可以选择性的进行同步更新操作语法:
sql
INSERT ... ON DUPLICATE KEY UPDATE
column = value [, column = value] ...
着意味着发生了唯一型冲突后才会执行UPDATE之后的语句:
- 无冲突,影响行数1
sql
mysql> insert into students values(6,23106,'沙悟净',null) on duplicate key update id=10;
Query OK, 1 row affected (0.02 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
| 5 | 23105 | 孙仲谋 | NULL |
| 6 | 23106 | 沙悟净 | NULL |
+----+-------+-----------+------+
6 rows in set (0.00 sec)
- 有冲突,且插入值与原值不同,影响行数2
sql
mysql> insert into students values(6,23106,'沙悟净',null) on duplicate key update id=10;
Query OK, 2 rows affected (0.01 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
| 5 | 23105 | 孙仲谋 | NULL |
| 10 | 23106 | 沙悟净 | NULL |
+----+-------+-----------+------+
6 rows in set (0.00 sec)
- 有冲突,且插入值与原值相同,影响行数0
sql
mysql> insert into students values(6,23106,'沙悟净',null) on duplicate key update id=10;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
| 5 | 23105 | 孙仲谋 | NULL |
| 10 | 23106 | 沙悟净 | NULL |
+----+-------+-----------+------+
6 rows in set (0.00 sec)
替换
我们可以直接用replace代替insert,如果没有冲突就是直接插入,如果发生了冲突就会删除然后插入:
sql
mysql> replace into students(sn,name) values(23106,'唐玄奘');
Query OK, 2 rows affected (0.01 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
| 5 | 23105 | 孙仲谋 | NULL |
| 11 | 23106 | 唐玄奘 | NULL |
+----+-------+-----------+------+
6 rows in set (0.00 sec)
mysql> replace into students(sn,name) values(23107,'李世民');
Query OK, 1 row affected (0.00 sec)
mysql> select * from students;
+----+-------+-----------+------+
| id | sn | name | qq |
+----+-------+-----------+------+
| 1 | 23101 | 刘玄德 | 8888 |
| 2 | 23102 | 关云长 | NULL |
| 3 | 23103 | 张翼德 | NULL |
| 4 | 23104 | 曹孟德 | NULL |
| 5 | 23105 | 孙仲谋 | NULL |
| 11 | 23106 | 唐玄奘 | NULL |
| 12 | 23107 | 李世民 | NULL |
+----+-------+-----------+------+
7 rows in set (0.00 sec)
Retrieve
语法:
sql
SELECT
[DISTINCT] {* | {column [, column] ...}
[FROM table_name]
[WHERE ...]
[ORDER BY column [ASC | DESC], ...]
LIMIT ...
我们还是先创建表用于测试案例:
sql
mysql> CREATE TABLE exam_result (
-> id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
-> name VARCHAR(20) NOT NULL COMMENT '同学姓名',
-> chinese float DEFAULT 0.0 COMMENT '语文成绩',
-> math float DEFAULT 0.0 COMMENT '数学成绩',
-> english float DEFAULT 0.0 COMMENT '英语成绩'
-> );
Query OK, 0 rows affected (0.04 sec)
再插入部分数据:
sql
mysql> INSERT INTO exam_result (name, chinese, math, english) VALUES
-> ('唐三藏', 67, 98, 56),
-> ('孙悟空', 87, 78, 77),
-> ('猪悟能', 88, 98, 90),
-> ('曹孟德', 82, 84, 67),
-> ('刘玄德', 55, 85, 45),
-> ('孙权', 70, 73, 78),
-> ('宋公明', 75, 65, 30);
Query OK, 7 rows affected (0.01 sec)
Records: 7 Duplicates: 0 Warnings: 0
SElECT列
全列查询
全列查询我们用的非常多了:

这里*就是全列查询。
但通常来说不建议使用全列查询
- 查询的列越多,意味着需要传输的数据量越大;
- 可能会影响到索引的使用。
指定列查询
我们可以选定想要查询的列:

而且我们无需遵循原表顺序,甚至可以:

查询字段为表达式
我们可以在select后面加上一些表达式:
sql
mysql> select name,id+10,1,1+1 from exam_result;
+-----------+-------+---+-----+
| name | id+10 | 1 | 1+1 |
+-----------+-------+---+-----+
| 唐三藏 | 11 | 1 | 2 |
| 孙悟空 | 12 | 1 | 2 |
| 猪悟能 | 13 | 1 | 2 |
| 曹孟德 | 14 | 1 | 2 |
| 刘玄德 | 15 | 1 | 2 |
| 孙权 | 16 | 1 | 2 |
| 宋公明 | 17 | 1 | 2 |
+-----------+-------+---+-----+
7 rows in set (0.00 sec)
为查询结果指定别名
在查询列后加as newcolname就能给列指定别名,as还可以省略。
此外不仅能给原列指定别名,还能给表达式指定别名:
sql
mysql> select name as 姓名,id ID,chinese+english+math 总分 from exam_result;
+-----------+----+--------+
| 姓名 | ID | 总分 |
+-----------+----+--------+
| 唐三藏 | 1 | 221 |
| 孙悟空 | 2 | 242 |
| 猪悟能 | 3 | 276 |
| 曹孟德 | 4 | 233 |
| 刘玄德 | 5 | 185 |
| 孙权 | 6 | 221 |
| 宋公明 | 7 | 170 |
+-----------+----+--------+
7 rows in set (0.00 sec)
结果去重
sql
mysql> select math from exam_result;
+------+
| math |
+------+
| 98 |
| 78 |
| 98 |
| 84 |
| 85 |
| 73 |
| 65 |
+------+
7 rows in set (0.00 sec)
可以看到98分重复了,我们可以加上distinct关键字去重:
sql
mysql> select distinct math from exam_result;
+------+
| math |
+------+
| 98 |
| 78 |
| 84 |
| 85 |
| 73 |
| 65 |
+------+
6 rows in set (0.05 sec)
WHERE条件
我们可以在查询时跟上where和比较运算符.
比较运算符:
| 运算符 | 说明 |
|---|---|
>, >=, <, <= |
大于,大于等于,小于,小于等于 |
= |
等于,NULL 不安全,例如 NULL = NULL 的结果是 NULL |
<=> |
等于,NULL 安全,例如 NULL <=> NULL 的结果是 TRUE(1) |
!=, <> |
不等于 |
BETWEEN a0 AND a1 |
范围匹配,[a0, a1],如果 a0 <= value <= a1,返回 TRUE(1) |
IN (option, ...) |
如果是 option 中的任意一个,返回 TRUE(1) |
IS NULL |
是 NULL |
IS NOT NULL |
不是 NULL |
LIKE |
模糊匹配。% 表示任意多个(包括 0 个)任意字符;_ 表示任意一个字符 |
逻辑运算符:
| 运算符 | 说明 |
|---|---|
AND |
多个条件必须都为 TRUE(1),结果才是 TRUE(1) |
OR |
任意一个条件为 TRUE(1),结果为 TRUE(1) |
NOT |
条件为 TRUE(1),结果为 FALSE(0) |
=和!=这些运算对NULL运算是不安全的,所以更常用IS NULL来进行判空。
我们来做一些尝试:
-
英语不及格的同学及英语成绩 ( < 60 )

-
语文成绩在 [80, 90] 分的同学及语文成绩

-
数学成绩是 58 或者 59 或者 98 或者 99 分的同学及数学成绩

-
姓孙的同学 及 孙某同学

-
语文成绩好于英语成绩的同学

-
总分在 200 分以下的同学

这时候就有一个问题,我们where后面能不能用总分这个别名?

答案是不能,原因很简单,我们分析一下查询的顺序:

我们查询表首先得要找到表的位置,其次根据条件筛选数据,最后才是选择列。因此where还不知道总分这个别名。
-
语文成绩 > 80 并且不姓孙的同学

-
孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80

9.NULL查询


结果排序
我们还能对结果进行排序:
sql
-- ASC(Ascending) 为升序(从小到大)
-- DESC(Descending) 为降序(从大到小)
-- 默认为 ASC
SELECT ... FROM table_name [WHERE ...]
ORDER BY column [ASC|DESC], [...];
注意:没有 ORDER BY 子句的查询,返回的顺序是未定义的,永远不要依赖这个顺序,即使你是有序插入的。
使用示例:
- 同学及数学成绩,按数学成绩升序显示

- 同学及 qq 号,按 qq 号排序显示

着意味着NULL视为最小的值。 - 查询同学各门成绩,依次按 数学降序,英语升序,语文升序的方式显示

- 查询同学及总分,由高到低

注意到我们这时又可以使用总分这个别名了。这是因为我们都是在筛选之后再进行排序的,技术上来说我们可以在筛选前排序,但这是比较浪费的。因此order by执行顺序在重命名后。 - 查询姓孙的同学或者姓曹的同学数学成绩,结果按数学成绩由高到低显示

筛选分页结果
有时候查询结果太多,我们可以用limit关键字进行分页:
sql
-- 起始下标为 0 -- 从 0 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n;
-- 从 s 开始,筛选 n 条结果
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT s, n
;
-- 从 s 开始,筛选 n 条结果,比第二种用法更明确,建议使用
SELECT ... FROM table_name [WHERE ...] [ORDER BY ...] LIMIT n OFFSET s;
如:
sql
mysql> select * from exam_result limit 3;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 1 | 唐三藏 | 67 | 98 | 56 |
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
+----+-----------+---------+------+---------+
3 rows in set (0.00 sec)
mysql> select * from exam_result limit 1,3;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
+----+-----------+---------+------+---------+
3 rows in set (0.00 sec)
mysql> select * from exam_result limit 3 offset 1;
+----+-----------+---------+------+---------+
| id | name | chinese | math | english |
+----+-----------+---------+------+---------+
| 2 | 孙悟空 | 87 | 78 | 77 |
| 3 | 猪悟能 | 88 | 98 | 90 |
| 4 | 曹孟德 | 82 | 84 | 67 |
+----+-----------+---------+------+---------+
3 rows in set (0.00 sec)
Update
语法:
sql
UPDATE table_name SET column = expr [, column = expr ...]
[WHERE ...] [ORDER BY ...] [LIMIT ...]
可以看到我们更新是针对列更新的,因此最好加上where否则会整列更新。
示例:
- 将孙悟空同学的数学成绩变更为 80 分

- 将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分

- 将总成绩倒数前三的 3 位同学的数学成绩加上 30 分

- 将所有同学的语文成绩更新为原来的 2 倍
sql
mysql> select name,chinese from exam_result;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 唐三藏 | 67 |
| 孙悟空 | 87 |
| 猪悟能 | 88 |
| 曹孟德 | 70 |
| 刘玄德 | 55 |
| 孙权 | 70 |
| 宋公明 | 75 |
+-----------+---------+
7 rows in set (0.00 sec)
mysql> update exam_result set chinese=2*chinese;
Query OK, 7 rows affected (0.01 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql> select name,chinese from exam_result;
+-----------+---------+
| name | chinese |
+-----------+---------+
| 唐三藏 | 134 |
| 孙悟空 | 174 |
| 猪悟能 | 176 |
| 曹孟德 | 140 |
| 刘玄德 | 110 |
| 孙权 | 140 |
| 宋公明 | 150 |
+-----------+---------+
7 rows in set (0.00 sec)
Delete
删除数据
语法:
sql
DELETE FROM table_name [WHERE ...] [ORDER BY ...] [LIMIT ...]
示例:
- 删除孙悟空同学的考试成绩

- 删除整张表数据
我们先准备一个测试用的表:
sql
mysql> CREATE TABLE for_delete (
-> id INT PRIMARY KEY AUTO_INCREMENT,
-> name VARCHAR(20)
-> );
Query OK, 0 rows affected (0.06 sec)
mysql> INSERT INTO for_delete (name) VALUES ('A'), ('B'), ('C');
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM for_delete;
+----+------+
| id | name |
+----+------+
| 1 | A |
| 2 | B |
| 3 | C |
+----+------+
3 rows in set (0.00 sec)
删除整张表:

注意此时只是删除了数据,表的结构在,我们可以看看创建语句:

可以看到自增长的值为4,这意味着我们再插入数据也是从4开始增长:

截断表
语法:
sql
TRUNCATE [TABLE] table_name
注意:这个操作慎用
- 只能对整表操作,不能像 DELETE 一样针对部分数据操作;
- 实际上 MySQL 不对数据操作,所以比 DELETE 更快,但是TRUNCATE在删除数据的时候,并不经过真正的事务,所以无法回滚
- 会重置 AUTO_INCREMENT 项
我们先准备测试用例:

截断表:

此外他还会将自增长的数值清零:


插入查询结果
我们可以将查询结果直接插入到表中,语法:
sql
INSERT INTO table_name [(column [, column ...])] SELECT ...
例如:删除表中的的重复复记录,重复的数据只能有一份
我们先创建测试用表:
sql
mysql> CREATE TABLE duplicate_table (id int, name varchar(20));
Query OK, 0 rows affected (0.04 sec)
mysql> INSERT INTO duplicate_table VALUES
-> (100, 'aaa'),
-> (100, 'aaa'),
-> (200, 'bbb'),
-> (200, 'bbb'),
-> (200, 'bbb'),
-> (300, 'ccc');
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from duplicate_table;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 100 | aaa |
| 200 | bbb |
| 200 | bbb |
| 200 | bbb |
| 300 | ccc |
+------+------+
6 rows in set (0.00 sec)
具体实现思路是新建一个相同的表结构,然后将旧表数据去重后插入新表,最后对两表重命名:
先创建表结构,拷贝创建语句即可:
sql
mysql> show create table duplicate_table \G
*************************** 1. row ***************************
Table: duplicate_table
Create Table: CREATE TABLE `duplicate_table` (
`id` int DEFAULT NULL,
`name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)
mysql> CREATE TABLE `new_duplicate_table` (
-> `id` int DEFAULT NULL,
-> `name` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL
-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
-> ;
Query OK, 0 rows affected (0.05 sec)
或者可以用like语句:
sql
mysql> drop table new_duplicate_table;
Query OK, 0 rows affected (0.03 sec)
mysql> create table no_duplicate_table like duplicate_table;
Query OK, 0 rows affected (0.04 sec)
然后插入去重后数据:
sql
mysql> insert into no_duplicate_table select distinct * from duplicate_table;
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from no_duplicate_table;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
+------+------+
3 rows in set (0.00 sec)
最后通过重命名实现原子去重操作:
sql
mysql> rename table duplicate_table to old_duplicate_table, no_duplicate_table to duplicate_table;
Query OK, 0 rows affected (0.06 sec)
mysql> select * from duplicate_table;
+------+------+
| id | name |
+------+------+
| 100 | aaa |
| 200 | bbb |
| 300 | ccc |
+------+------+
3 rows in set (0.00 sec)
聚合函数
有时候我们需要对查询的数据做一定统计,这时候就需要用到聚合函数:
| 函数 | 说明 |
|---|---|
COUNT([DISTINCT] expr) |
返回查询到的数据的数量 |
SUM([DISTINCT] expr) |
返回查询到的数据的总和,非数字类型无意义 |
AVG([DISTINCT] expr) |
返回查询到的数据的平均值,非数字类型无意义 |
MAX([DISTINCT] expr) |
返回查询到的数据的最大值,非数字类型无意义 |
MIN([DISTINCT] expr) |
返回查询到的数据的最小值,非数字类型无意义 |
- 统计班级有多少名同学:

- 统计班级收集的 qq 号有多少

这是因为null不计入统计:

- 统计本次考试的数学成绩分数个数

还可以统计去重后的数据:

- 统计数学成绩总分

还可以统计数学不及格的数学总分:

- 统计平均总分

- 返回英语最高分

- 返回 > 70 分以上的数学最低分

SQL执行顺序
- FROM → 定位数据源表
- WHERE → 分组前过滤行(只保留符合条件的行,不能用聚合函数)
- GROUP BY → 对过滤后的行分组
- SELECT → 计算聚合函数、筛选要显示的字段
- HAVING → 分组后过滤分组(只能用分组字段 / 聚合函数)
- ORDER BY → 对最终结果排序
- LIMIT → 限制返回的行数
SQL查询中各个关键字的执行先后顺序 from > on> join > where > group by > with > having > select> distinct > order by > limit
group by子句的使用
在select中使用group by 子句可以对指定列进行分组查询
sql
select column1, column2, .. from table group by column;
我们要明确分组查询的目的是使用聚合函数。
我们先准备一份信息数据
数据基本结构:
sql
mysql> use scott;
Database changed
mysql> show tables;
+-----------------+
| Tables_in_scott |
+-----------------+
| dept |
| emp |
| salgrade |
+-----------------+
3 rows in set (0.00 sec)
mysql> desc dept;
+--------+--------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------------------+------+-----+---------+-------+
| deptno | int(2) unsigned zerofill | NO | | NULL | |
| dname | varchar(14) | YES | | NULL | |
| loc | varchar(13) | YES | | NULL | |
+--------+--------------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> desc emp;
+----------+--------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------------------+------+-----+---------+-------+
| empno | int(6) unsigned zerofill | NO | | NULL | |
| ename | varchar(10) | YES | | NULL | |
| job | varchar(9) | YES | | NULL | |
| mgr | int(4) unsigned zerofill | YES | | NULL | |
| hiredate | datetime | YES | | NULL | |
| sal | decimal(7,2) | YES | | NULL | |
| comm | decimal(7,2) | YES | | NULL | |
| deptno | int(2) unsigned zerofill | YES | | NULL | |
+----------+--------------------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
mysql> desc salgrade;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| grade | int | YES | | NULL | |
| losal | int | YES | | NULL | |
| hisal | int | YES | | NULL | |
+-------+------+------+-----+---------+-------+
3 rows in set (0.00 sec)
- 显示每个部门的平均工资和最高工资

分组针对聚合函数,原则上处理分组的元素和聚合函数,其他元素都不能select出来:

- 显示每个部门的每种岗位的平均工资和最低工资

- 显示平均工资低于2000的部门和它的平均工资

having和where类似,但是having是对分组之后结果进行筛选。
OJ
sql
insert into actor values(1,'PENELOPE','GUINESS','2006-02-15 12:34:33'),
(2,'NICK','WAHLBERG','2006-02-15 12:34:33');
sql
select distinct salary from salaries order by salary desc;
sql
select * from employees order by hire_date desc limit 1;
sql
select * from employees where hire_date=(
select distinct hire_date from employees
order by hire_date desc limit 2,1
);
sql
select emp_no,count(1) from salaries group by emp_no having count(1)>15;
sql
select title,count(1) t from titles group by title having t>1;
sql
select Email from Person group by email having count(1)>1;
sql
select name,population,area from World where population>=25000000 or
area >=3000000;