SQL语句学习

SQL语句学习

SQL语句注意事项:

  1. SQL 对大小写不敏感:SELECT 与 select 是相同的。
  2. 一些最重要的sql语句
---对表中的记录操作
SELECT...FROM TABLE - 从数据库中提取数据
UPDATE TABLE SET column1=value1,column2=value2,... WHERE ... - 更新数据库中的数据
DELETE FROM TABLE WHERE ... - 从数据库中删除数据
INSERT INTO TABLE VALUES - 向数据库中插入新数据
---对数据库操作
CREATE DATABASE - 创建新数据库
ALTER DATABASE - 修改数据库
DROP DATABASE -删除数据库
---对表操作
CREATE TABLE - 创建新表
ALTER TABLE - 变更(改变)数据库表, 增删改约束/增删改列属性
DROP TABLE - 删除表
---对索引操作
CREATE INDEX - 创建索引(搜索键)
DROP INDEX - 删除索引
---对视图操作
CREATE VIEW... AS SELECT... --创建视图
CREATE OR REPLACE VIEW... AS SELECT -- 修改更新视图 
DROP VIEW VIEWNAME -- 删除视图
  1. sql执行顺序 :
    1. from
    2. join
    3. on
    4. where
    5. group by(开始使用select中的别名,后面的语句中都可以使用)
    6. avg,sum…
    7. having
    8. select
    9. distinct
    10. order by
    11. limit

MySQL 数据类型

在 MySQL 中,有三种主要的类型:Text(文本)、Number(数字)和 Date/Time(日期/时间)类型。

**Text 类型:**char、varchar、text

数据类型 描述
CHAR(size) 保存固定长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串的长度。最多 255 个字符。
VARCHAR(size) 保存可变长度的字符串(可包含字母、数字以及特殊字符)。在括号中指定字符串的最大长度。最多 255 个字符。**注释:**如果值的长度大于 255,则被转换为 TEXT 类型。
TINYTEXT 存放最大长度为 255 个字符的字符串。
TEXT 存放最大长度为 65,535 个字符的字符串。
BLOB 用于 BLOBs(Binary Large OBjects)。存放最多 65,535 字节的数据。
MEDIUMTEXT 存放最大长度为 16,777,215 个字符的字符串。
MEDIUMBLOB 用于 BLOBs(Binary Large OBjects)。存放最多 16,777,215 字节的数据。
LONGTEXT 存放最大长度为 4,294,967,295 个字符的字符串。
LONGBLOB 用于 BLOBs (Binary Large OBjects)。存放最多 4,294,967,295 字节的数据。
ENUM(x,y,z,etc.) 允许您输入可能值的列表。可以在 ENUM 列表中列出最大 65535 个值。如果列表中不存在插入的值,则插入空值。**注释:**这些值是按照您输入的顺序排序的。可以按照此格式输入可能的值: ENUM(‘X’,‘Y’,‘Z’)
SET 与 ENUM 类似,不同的是,SET 最多只能包含 64 个列表项且 SET 可存储一个以上的选择

**Number 类型:**int、float、double、decimal

数据类型 描述
TINYINT(size) 带符号-128到127 ,无符号0到255。
SMALLINT(size) 带符号范围-32768到32767,无符号0到65535, size 默认为 6。
MEDIUMINT(size) 带符号范围-8388608到8388607,无符号的范围是0到16777215。 size 默认为9
INT(size) 带符号范围-2147483648到2147483647,无符号的范围是0到4294967295。 size 默认为 11
BIGINT(size) 带符号的范围是-9223372036854775808到9223372036854775807,无符号的范围是0到18446744073709551615。size 默认为 20
FLOAT(size,d) 带有浮动小数点的小数字。在 size 参数中规定显示最大位数。在 d 参数中规定小数点右侧的最大位数。
DOUBLE(size,d) 带有浮动小数点的大数字。在 size 参数中规显示定最大位数。在 d 参数中规定小数点右侧的最大位数。
DECIMAL(size,d) 作为字符串存储的 DOUBLE 类型,允许固定的小数点。在 size 参数中规定显示最大位数。在 d 参数中规定小数点右侧的最大位数。

**注意:**以上的 size 代表的并不是存储在数据库中的具体的长度,如 int(4) 并不是只能存储4个长度的数字。

实际上int(size)所占多少存储空间并无任何关系。int(3)、int(4)、int(8) 在磁盘上都是占用 4 btyes 的存储空间。就是在显示给用户的方式有点不同外,int(M) 跟 int 数据类型是相同的。

例如:

1、int的值为10

int(9)显示结果为000000010
int(3)显示结果为010

就是显示的长度不一样而已 都是占用四个字节的空间

**Date 类型:**date、datetime、year

数据类型 描述
DATE() 日期。格式:YYYY-MM-DD **注释:**支持的范围是从 ‘1000-01-01’ 到 ‘9999-12-31’
DATETIME() *日期和时间的组合。格式:YYYY-MM-DD HH:MM:SS **注释:**支持的范围是从 ‘1000-01-01 00:00:00’ 到 ‘9999-12-31 23:59:59’
TIMESTAMP() *时间戳。TIMESTAMP 值使用 Unix 纪元(‘1970-01-01 00:00:00’ UTC) 至今的秒数来存储。格式:YYYY-MM-DD HH:MM:SS **注释:**支持的范围是从 ‘1970-01-01 00:00:01’ UTC 到 ‘2038-01-09 03:14:07’ UTC
TIME() 时间。格式:HH:MM:SS **注释:**支持的范围是从 ‘-838:59:59’ 到 ‘838:59:59’
YEAR() 2 位或 4 位格式的年。 **注释:**4 位格式所允许的值:1901 到 2155。2 位格式所允许的值:70 到 69,表示从 1970 到 2069。

*即便 DATETIME 和 TIMESTAMP 返回相同的格式,它们的工作方式很不同。在 INSERT 或 UPDATE 查询中,TIMESTAMP 自动把自身设置为当前的日期和时间。TIMESTAMP 也接受不同的格式,比如 YYYYMMDDHHMMSS、YYMMDDHHMMSS、YYYYMMDD 或 YYMMDD。

常用SQL操作

sql简单教程

  1. 数据库表操作:
use atguigu;   -- 命令用于选择数据库
set names utf8;    -- 命令用于设置使用的字符集
  1. SELECT 语句用于从数据库中选取数据。
SELECT * from t_book; -- 读取数据表的信息
select name, author from t_book;

SELECT语句中关键字的顺序

<SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>] 
基本顺序: ‘fromwheregrouphavingorderlimit

​ SELECT语句中子句的执行顺序与SELECT语句中子句的输入顺序是不一样的,所以并不是从SELECT子句开始执行的,而是按照下面的顺序执行:

开始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->SELECT子句->ORDER BY子句->LIMIT子句->最终结果

​ 上面只有select的执行位置有所不同,在limit前面执行

每个子句执行后都会产生一个中间结果,供接下来的子句使用,如果不存在某个子句,就跳过

  1. SELECT DISTINCT 语句用于返回唯一不同的值。---- 使用distinct,一般只查询一列属性
-- 在表中,一个列可能会包含多个重复值,有时您也许希望仅仅列出不同(distinct)的值。
select DISTINCT author from t_book; 
  1. WHERE 子句用于提取那些满足指定条件的记录。
-- SQL 使用单引号来环绕文本值(大部分数据库系统也接受双引号)。如果是数值字段,请不要使用引号。
select * from t_book where author = "国哥";
select * from t_book where price >= 50;
select * from t_book where author in ('国哥', '谭浩强');
select * from t_book where price between 50 and 100;
select * from t_book where name like 'c%';

下面的运算符可以在 WHERE 子句中使用:

运算符 描述
= 等于,在where子句中使用=号,mysql只允许返回一行数据,如果返回多行数据,请使用“in”关键字
<> 不等于。**注释:**在 MySQL 中,该操作符被写成 !=
> 大于
< 小于
>= 大于等于
<= 小于等于
BETWEEN… AND… 在某个范围内
LIKE 搜索某种模式
IN 指定针对某个列的多个可能值
  1. AND和OR 运算符用于基于一个以上的条件对记录进行过滤。
-- 如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录。
-- 如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录。
select * from t_book where price >= 50 and author = '国哥';
SELECT * FROM Websites WHERE country='CN' OR alexa > 50;
SELECT * FROM Websites WHERE alexa > 15 AND (country='CN' OR country='USA');
  1. ORDER BY 关键字用于对结果集进行排序。
-- ORDER BY 关键字默认按照升序对记录进行排序。如果需要按照降序对记录进行排序,您可以使用 DESC 关键字
-- 语法:SELECT column_name,column_nameFROM table_nameORDER BY column_name,column_name ASC|DESC;
select id, name, price from t_book order by price;
select id, name, price from t_book order by price desc;

-- ORDER BY 多列的时候,先按照第一个column name排序,在按照第二个column name排序
select * from t_book order by price desc, sales desc;
  1. insert into语法 — 插入新纪录
INSERT INTO 语句可以有两种编写形式:
第一种形式无需指定要插入数据的列名,只需提供被插入的值即可
INSERT INTO table_name VALUES (value1,value2,value3,...);

第二种形式需要指定列名及被插入的值,其他未插入的列属性默认用null
INSERT INTO table_name (column1,column2,column3,...) VALUES (value1,value2,value3,...);

insert into t_book(name, author, price, sales, stock,img_path) values('c++从入门到精通', '叶志行',129 ,900 ,1000, 'static/img/default.jpg'); 

-- 一次性插入多条记录,用逗号,隔开
insert into actor values(1, "PENELOPE", "GUINESS", "2006-02-15 12:34:33"), (2, "NICK", "WAHLBERG", "2006-02-15 12:34:33");

-- 一般不向id添加数字,因为id 列是自动更新的,表中的每条记录都有一个唯一的数字。

三种插入方式:

insert into: 插入已存在, id会自增,但是插入不成功(主键重复),会报错

repalce into: (主键和unique键判断)已存在则替换,删除原来的记录,添加新的记录(如果没有声明主键,则新的记录放在末尾);不存在替换,添加新的记录

insert ignore into: 插入已存在,忽略新插入的记录,id会自增,不会报错;插入不存在,添加新的记录

replace into names(name, age) values("大名", 23);
replace into names(name, age) values("小明", 23);

insert ignore into names(name, age) values("大壮", 25);
insert ignore into names(name, age) values("壮壮", 25);
  1. UPDATE 语句用于更新表中已存在的记录。
语法:
UPDATE table_name SET column1=value1,column2=value2,... WHERE some_column=some_value;
--- WHERE 子句规定哪条记录或者哪些记录需要更新。如果您省略了 WHERE 子句,所有的记录都将被更新!

update t_book set stock = 100, price = 89 where name = 'c++从入门到精通';
  1. DELETE 语句用于删除表中的行。
语法:DELETE FROM table_name WHERE some_column=some_value;

DELETE FROM Websites WHERE name='Facebook' AND country='USA';
DELETE FROM table_name; / DELETE * FROM table_name; --- 表示删除所有行记录,表结构、属性、索引将保持不变

请注意 SQL DELETE 语句中的 WHERE 子句!

WHERE 子句规定哪条记录或者哪些记录需要删除。如果您省略了 WHERE 子句,所有的记录都将被删除!

在删除记录时要格外小心!因为您不能重来!

sql高级教程

limit/like/in/between/通配符/别名
  1. SELECT TOP 子句用于规定要返回的记录的数目
-- 并非所有的数据库系统都支持 SELECT TOP 语句。 MySQL 支持 LIMIT 语句来选取指定的条数数据, Oracle 可以使用 ROWNUM 来选取。
SELECT column_name(s) FROM table_name LIMIT number;
SELECT * FROM Persons LIMIT 5; //取前5条记录

--LIMIT m,n : 表示从第m+1条开始,取n条数据; --- mysql中记录从0开始自增
--LIMIT n : 表示从第0条开始,取n条数据,是limit(0,n)的缩写。
  1. LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式。
语法:SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern;

SELECT * FROM Websites WHERE name LIKE 'G%';  -- 选取name以G开头的网站记录
SELECT * FROM Websites WHERE name LIKE '%k';  -- 选取name以k结尾的网站记录
  1. SQL 通配符----在 SQL 中,通配符与 SQL LIKE 操作符一起使用。SQL 通配符用于搜索表中的数据。
通配符 描述
% 替代 0 个或多个字符
_ 替代一个字符
[charlist] 字符列中的任何单一字符
[^charlist] 或 [!charlist] 不在字符列中的任何单一字符
SELECT * FROM Websites WHERE url LIKE 'https%';
SELECT * FROM Websites WHERE url LIKE '%oo%';
SELECT * FROM Websites WHERE name LIKE '_oogle';
SELECT * FROM Websites WHERE name LIKE 'G_o_le'
-- MySQL 中使用 REGEXP 或 NOT REGEXP 运算符 (或 RLIKE 和 NOT RLIKE) 来操作正则表达式。
SELECT * FROM Websites WHERE name REGEXP '^[GFs]'; -- 选取 name 以 "G"、"F" 或 "s" 开始的所有网站
SELECT * FROM Websites WHERE name REGEXP '^[A-H]'; -- 选取 name 以 A 到 H 字母开头的网站
SELECT * FROM Websites WHERE name REGEXP '^[^A-H]'; -- 选取 name 不以 A 到 H 字母开头的网站
  1. IN 操作符允许您在 WHERE 子句中规定多个值,NOT IN表示不在
语法:SELECT column_name(s) FROM table_name WHERE column_name IN (value1,value2,...);

SELECT * FROM Websites WHERE name IN ('Google','菜鸟教程');

-- 使用NOT IN选出在employees但不在dept_manager中的emp_no记录
select emp_no from employees where emp_no not in (select emp_no from dept_manager);
-- 先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录
SELECT emp_no FROM (SELECT * FROM employees LEFT JOIN dept_manager ON employees.emp_no = dept_manager.emp_no) WHERE dept_no IS NULL;
-- left join的升级形式,使用单层SELECT语句即可
SELECT employees.emp_no FROM employees LEFT JOIN dept_manager ON employees.emp_no = dept_manager.emp_no WHERE dept_no IS NULL;

--in关键字适合确定数量的情况,一般效率较低,不推荐使用。能用in关键字的语句都可以转化为使用join的语句,推荐使用join关键字。

select 语句查询到单列属性的值时,可以作为值来使用,如上语句

  1. BETWEEN 操作符选取介于两个值之间的数据范围内的值(包括边界值)。这些值可以是数值、文本或者日期
SELECT * FROM Websites WHERE alexa BETWEEN 1 AND 20;
SELECT * FROM Websites WHERE alexa NOT BETWEEN 1 AND 20;
SELECT * FROM Websites WHERE name BETWEEN 'A' AND 'H';
SELECT * FROM Websites WHERE name NOT BETWEEN 'A' AND 'H';
SELECT * FROM access_log WHERE date BETWEEN '2016-05-10' AND '2016-05-14';
  1. SQL别名,可以为表名称列名称指定别名。

    基本上,创建别名是为了让列名称的可读性更强。

SELECT column_name AS alias_name FROM table_name; -- 列的别名
SELECT column_name(s) FROM table_name AS alias_name; -- 表的别名

-- 指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。提示:如果列名称包含空格,要求使用双引号或方括号
SELECT name AS n, country AS c FROM Websites; 
-- 我们把三个列(url、alexa 和 country)结合在一起,并创建一个名为 "site_info" 的别名,concat关键字的使用
SELECT name, CONCAT(url, ', ', alexa, ', ', country) AS site_info FROM Websites;


-- 我们使用 "Websites" 和 "access_log" 表,并分别为它们指定表别名 "w" 和 "a"(通过使用别名让 SQL 更简短):
SELECT w.name, w.url, a.count, a.date FROM Websites AS w, access_log AS a WHERE a.site_id=w.id and w.name="菜鸟教程";  --类似于join操作

-- 也可以省略as关键字
SELECT e.emp_no FROM employees e LEFT JOIN dept_manager d ON e.emp_no = d.emp_no WHERE dept_no is NULL

下面的情况下,使用别名很有用:
    在查询中涉及超过一个表
    在查询中使用了函数
    列名称很长或者可读性差
    需要把两个列或者多个列结合在一起
join操作
  1. SQL join 用于把来自两个或多个表的行结合起来。

下图展示了 LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 相关的 7 种用法。

SQL语句学习_第1张图片

sql join类型说明:

  • INNER JOIN:如果表中有至少一个匹配,则返回行 ----
  • LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN:只要其中一个表中存在匹配,则返回行 ----- mysql中不支持

在使用 join 时,onwhere 条件的区别如下:

  • 1、 on 条件是在生成临时表时,合并两表时使用的条件
  • 2、where 条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有 left join 的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。
-- inner join(最常见最简单), SQL INNER JOIN 从多个表中返回满足 JOIN 条件的所有行
SELECT column_name(s) FROM table1 INNER JOIN table2 ON table1.column_name=table2.column_name;
SELECT column_name(s) FROM table1 JOIN table2 ON table1.column_name=table2.column_name;
-- INNER JOIN 与 JOIN 是相同的。

SELECT Websites.id, Websites.name, access_log.count, access_log.date FROM Websites INNER JOIN access_log ON Websites.id=access_log.site_id;

SELECT Websites.name, access_log.count, access_log.date FROM Websites INNER JOIN access_log ON Websites.id=access_log.site_id ORDER BY access_log.count; -- 增加排序
-- INNER JOIN 关键字在表中存在至少一个匹配时返回行。如果 "Websites" 表中的行在 "access_log" 中没有匹配,则不会列出这些行。

-- LEFT JOIN 关键字从左表(table1)返回所有的行,即使右表(table2)中没有匹配。如果右表中没有匹配,则结果为 NULL。
SELECT column_name(s) FROM table1 LEFT JOIN table2 ON table1.column_name=table2.column_name;
SELECT column_name(s) FROM table1 LEFT OUTER JOIN table2 ON table1.column_name=table2.column_name;
-- 在某些数据库中,LEFT JOIN 称为 LEFT OUTER JOIN

SELECT Websites.name, access_log.count, access_log.date FROM Websites LEFT JOIN access_log ON Websites.id=access_log.site_id ORDER BY access_log.count DESC;

-- RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。
SELECT column_name(s) FROM table1 RIGHT JOIN table2 ON table1.column_name=table2.column_name;
SELECT column_name(s) FROM table1 RIGHT OUTER JOIN table2 ON table1.column_name=table2.column_name;
-- 在某些数据库中,RIGHT JOIN 称为 RIGHT OUTER JOIN

-- FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行.
-- FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。
SELECT column_name(s) FROM table1 FULL OUTER JOIN table2 ON table1.column_name=table2.column_name;

-- MySQL中不支持 FULL OUTER JOIN,你可以在 SQL Server 测试以下实例
SELECT Websites.name, access_log.count, access_log.date FROM Websites FULL OUTER JOIN access_log ON Websites.id=access_log.site_id ORDER BY access_log.count DESC;

where子句实现表连接

    利用 WHERE 子句建立联结关系似乎有点奇怪,但实际上,有一个很充分的理由。请记住,在一条 SELECT 语句中联结几个表时,相应的
关系是在运行中构造的。在数据库表的定义中不存在能指示MySQL如何对表进行联结的东西。你必须自己做这件事情。在联结两个表时,你实际上做
的是将第一个表中的每一行与第二个表中的每一行配对。 WHERE 子句作为过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。没有
WHERE 子句,第一个表中的每个行将与第二个表中的每个行配对(笛卡尔乘积,又叫叉连接),而不管它们逻辑上是否可以配在一起。
    不要忘了 WHERE 子句 应该保证所有联结都有 WHERE 子句,否则MySQL将返回比想要的数据多得多的数据。同理,应该保证 WHERE 
子句的正确性。不正确的过滤条件将导致MySQL返回不正确的数据。


内部联结
目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内部联结。其实,对于这种联结可以使用稍微
不同的语法来明确指定联结的类型。下面的 SELECT 语句返回与前面例子完全相同的数据:
select vend_name,prod_name,prod_price from vendors inner join products on vendors.vend_id = products.vend_id;
分析:此语句中的 SELECT 与前面的 SELECT 语句相同,但 FROM 子句不同。这里,两个表之间的关系是 FROM 子句的组成部分,以 
INNERJOIN 指定。在使用这种语法时,联结条件用特定的 ON 子句而不是 WHERE子句给出。传递给 ON 的实际条件与传递给 WHERE 的相
同。

使用哪种语法 ANSI SQL规范首选 INNER JOIN 语法。此外,尽管使用 WHERE 子句定义联结的确比较简单,但是使用明确的联结语法能够
确保不会忘记联结条件,有时候这样做也能影响性能。

联结多个表
SQL对一条 SELECT 语句中可以联结的表的数目没有限制。创建联结的基本规则也相同。首先列出所有表,然后定义表之间的关系。例如:
select prod_name,vend_name,prod_price,quantity from orderitems,products,vendors where products.vend_id = vendors.vend_id and orderitems.prod_id = products.products.prod_id and order_num = 20005;
分析:此例子显示编号为 20005 的订单中的物品。订单物品存储在orderitems 表中。每个产品按其产品ID存储,它引用 products表中的产品。这些产品通过供应商ID联结到 vendors 表中相应的供应商,供应商ID存储在每个产品的记录中。这里的 FROM 子句列出了3个表,而WHERE 子句定义了这两个联结条件,而第三个联结条件用来过滤出订单20005 中的物品。

性能考虑: MySQL在运行时关联指定的每个表以处理联结。这种处理可能是非常耗费资源的,因此应该仔细,不要联结不必要的表。联结的表
越多,性能下降越厉害。
多做实验: 正如所见,为执行任一给定的SQL操作,一般存在不止一种方法。很少有绝对正确或绝对错误的方法。性能可能会受操作类型、表中
数据量、是否存在索引或键以及其他一些条件的影响。因此,有必要对不同的选择机制进行实验,以找出最适合具体情况的方法。
UNION 操作
  1. SQL UNION 操作符合并两个或多个 SELECT 语句的结果,对应列元素合并放在同一列中
--默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL
SELECT column_name(s) FROM table1 UNION SELECT column_name(s) FROM table2;
SELECT column_name(s) FROM table1 UNION ALL SELECT column_name(s) FROM table2;
-- UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。

SELECT country FROM Websites UNION SELECT country FROM apps ORDER BY country; -- 不允许重复
SELECT country FROM Websites UNION ALL SELECT country FROM apps ORDER BY country; -- 允许重复
SELECT country, name FROM Websites WHERE country='CN' UNION ALL SELECT country, app_name FROM apps WHERE country='CN' ORDER BY country; -- 加上where的union
SELECT INTO操作
  1. SELECT INTO 语句从一个表复制数据,然后把数据插入到另一个新表中。

    MySQL 数据库不支持 SELECT … INTO 语句

    但支持 [INSERT INTO … 已经存在的表…SELECT … from 原来的表] 。当然你可以使用以下语句来拷贝表结构及数据:

    CREATE TABLE 新表 AS SELECT * FROM 旧表 — 如果是mysql,那么as可去掉可不去掉

    -- 以下两种方式等效
    create table actor_name as select first_name, last_name from actor;
    
    create table actor_name(
        first_name varchar(45) not null,
        last_name varchar(45) not null
    );
    insert into actor_name select first_name, last_name from actor;
    
语法:---mysql中不支持
SELECT * INTO newtable [IN externaldb] FROM table1; -- 复制所有的列插入到新表中
SELECT column_name(s) INTO newtable [IN externaldb] FROM table1; -- 只复制希望的列插入到新表中

SELECT * INTO WebsitesBackup2016 FROM Websites; -- 创建 Websites 的备份复件:
SELECT name, url INTO WebsitesBackup2016 FROM Websites; -- 只复制一些列插入到新表中:
  1. INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中。目标表中任何已存在的行都不会受影响
INSERT INTO table2 SELECT * FROM table1; -- 一个表中复制所有的列插入到另一个已存在的表中
INSERT INTO table2 (column_name(s)) SELECT column_name(s) FROM table1; -- 只复制希望的列插入到另一个已存在的表中

INSERT INTO Websites (name, country) SELECT app_name, country FROM apps;
INSERT INTO Websites (name, country) SELECT app_name, country FROM apps WHERE id=1;
SQL建库建表
  1. CREATE DATABASE 语句用于创建数据库。
CREATE DATABASE my_db;
  1. CREATE TABLE 语句用于创建数据库中的表。表由行和列组成,每个表都必须有个表名。
CREATE TABLE table_name
(
    column_name1 data_type(size),
    column_name2 data_type(size),
    column_name3 data_type(size),
....
);

CREATE TABLE Persons
(
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);

--     修改表名, rename to关键字
ALTER TABLE titles_test RENAME TO titles_2017;
RENAME TABLE titles_test to titles_2017;
SQL 约束
  1. SQL 约束 (constraints) 用于规定表中的数据规则。如果存在违反约束的数据行为,行为会被约束终止。

约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)。

在 SQL 中,我们有如下约束:

  • NOT NULL - 指示某列不能存储 NULL 值。
  • UNIQUE - 保证某列的每行必须有唯一的值。
  • PRIMARY KEY - 主键约束,NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标识,有助于更容易更快速地找到表中的一个特定的记录。
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件。
  • DEFAULT - 规定没有给列赋值时的默认值。
CREATE TABLE table_name
(
    column_name1 data_type(size) constraint_name,
    column_name2 data_type(size) constraint_name,
    column_name3 data_type(size) constraint_name,
    ....
);

create table student(
    Stuid int not null primary key  AUTO_INCREMENT,
    Stuage int not null CHECK (Stuage >0)
    Stuname VARCHAR(255) not null  unique,
    Stugender VARCHAR(100)  DEFAULT '男',
//    unique(Stuname, Stuid),
//    primary key(Stuid)
//    foreigh key(Stuname) REFERENCES t_user(username),
//    CHECK (P_Id>0)

    -- 只在前面加上 contraint contraints_name 
//  CONSTRAINT uc_PersonID UNIQUE (P_Id,LastName),  -- 命名 UNIQUE 约束为uc_PersonID,并定义多个列的unique约束   
//    CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName), -- 命名主键约束
//  CONSTRAINT fk_PerOrders FOREIGN KEY (P_Id)  REFERENCES Persons(P_Id) ---- 命名 FOREIGN KEY 约束,并定义多个列的 FOREIGN KEY 约束
//  CONSTRAINT chk_Person CHECK (P_Id>0 AND City='Sandnes')

);
-- 对于表中的约束,使用alter关键字修改,使用add关键字添加约束,使用drop关键字删除约束
ALTER TABLE Persons MODIFY Age int NOT NULL; -- 添加not null约束
ALTER TABLE Persons MODIFY Age int NULL; -- 删除not null约束

ALTER TABLE Persons ADD UNIQUE (P_Id)  -- 添加Unique约束
ALTER TABLE Persons ADD CONSTRAINT uc_PersonID UNIQUE (P_Id,LastName) -- 添加Unique约束并命名
ALTER TABLE Persons DROP INDEX uc_PersonID -- 撤销Unique约束

ALTER TABLE Persons ADD PRIMARY KEY (P_Id) -- 添加主键约束
ALTER TABLE Persons ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName) -- 添加主键约束并命名
ALTER TABLE Persons DROP PRIMARY KEY -- 删除主键约束

-- 一个表中的 FOREIGN KEY 指向另一个表中的 UNIQUE KEY(唯一约束的键)。
ALTER TABLE Orders ADD FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
ALTER TABLE Orders ADD CONSTRAINT fk_PerOrders FOREIGN KEY (P_Id) REFERENCES Persons(P_Id) -- 添加外键约束
ALTER TABLE Orders DROP FOREIGN KEY fk_PerOrders --撤销外键约束

ALTER TABLE Persons ADD CHECK (P_Id>0)
ALTER TABLE Persons ADD CONSTRAINT chk_Person CHECK (P_Id>0 AND City='Sandnes')--添加check约束并命名
ALTER TABLE Persons DROP CONSTRAINT chk_Person -- 撤销check约束

ALTER TABLE Persons ALTER City SET DEFAULT 'SANDNES'
ALTER TABLE Persons ADD CONSTRAINT ab_c DEFAULT 'SANDNES' for City -- 添加default约束
ALTER TABLE Persons ALTER City DROP DEFAULT -- 撤销default约束

-- Auto-increment 会在新记录插入表中时生成一个唯一的数字
-- 默认地,AUTO_INCREMENT 的开始值是 1,每条新记录递增 1。要让 AUTO_INCREMENT 序列以其他的值起始,请使用下面的 SQL 语法:
ALTER TABLE Persons AUTO_INCREMENT=100 

-- 修改表名
ALTER TABLE res_resource_tag RENAME  commercial_resource_tag;
-- 修改字段名
ALTER  TABLE 表名 CHANGE 旧字段名 新字段名 新数据类型; 
sql索引
  1. CREATE INDEX 语句用于在表中创建索引。
CREATE INDEX index_name ON table_name (column_name); -- 在表上创建一个简单的索引。允许使用重复的值
CREATE UNIQUE INDEX index_name ON table_name (column_name);  -- 在表上创建一个唯一的索引。即不允许使用重复的值:唯一的索引意味着两个行记录不能拥有相同的索引值

CREATE INDEX PIndex ON Persons (LastName) -- 在 "Persons" 表的 "LastName" 列上创建一个名为 "PIndex" 的索引
CREATE INDEX PIndex ON Persons (LastName, FirstName)  -- 索引不止一个列,您可以在括号中列出这些列的名称,用逗号隔开

-- 索引的使用,强制索引使用FORCE INDEX(indexname)关键字

select * from salaries force index(idx_emp_no) where emp_no = 10005;
-- 针对salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005, 使用强制索引。
  1. 使用 DROP 语句,可以轻松地删除索引、表和数据库
ALTER TABLE table_name DROP INDEX index_name; -- 删除表中的索引。

DROP TABLE table_name -- 删除表

DROP DATABASE database_name -- 删除数据库

TRUNCATE TABLE table_name -- 删除表内数据,但是不删除表本身
  1. ALTER TABLE 语句用于在已有的表中添加、删除或修改列。
ALTER TABLE table_name ADD column_name datatype  -- 添加表中的列
-- 在last_update后面新增加一列名字为create_date, 类型为datetime, NOT NULL,默认值为'2020-10-01 00:00:00'
-- 选择插入位置,使用after关键字
alter table actor add column create_date datetime not null default '2020-10-01 00:00:00' after last_update;


ALTER TABLE table_name DROP COLUMN column_name -- 删除表中的列
ALTER TABLE table_name MODIFY/ALTER COLUMN column_name datatype -- 修改列中的数据类型
SQL 视图
  1. SQL 视图(Views)。视图是可视化的表。

    在 SQL 中,视图是基于 SQL 语句的结果集的可视化的表。

    视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实的表中的字段。

    您可以向视图添加 SQL 函数、WHERE 以及 JOIN 语句,也可以呈现数据,就像这些数据来自于某个单一的表一样

    视图总是显示最新的数据!每当用户查询视图时,数据库引擎通过使用视图的 SQL 语句重建数据

-- 创建视图
CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition --- mysql中as可省略
--------
-- 实例:创建视图 "Current Product List" 会从 "Products" 表列出所有正在使用的产品(未停产的产品)
CREATE VIEW [Current Product List] AS SELECT ProductID,ProductName FROM Products WHERE Discontinued=No;

SELECT * FROM [Current Product List]; -- 查询上面这个视图
SELECT * FROM [Current Product List] where ProductID > 10; -- 有条件的查询这个视图

-- 更新视图,有这个视图则替换,无这个视图,则创建
CREATE OR REPLACE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition
-------
-- 实例:向 "Current Product List" 视图添加 "Category" 列。也就是视图的更新操作
CREATE VIEW [Current Product List] AS SELECT ProductID,ProductName,Category FROM Products WHERE Discontinued=No

-- 通过 DROP VIEW 命令来删除视图。
DROP VIEW view_name;  
  1. SQL Date 函数 ----- 下面的表格列出了 MySQL 中最重要的内建日期函数:
函数 描述
NOW() 返回当前的日期和时间
CURDATE() 返回当前的日期
CURTIME() 返回当前的时间
DATE() 提取日期或日期/时间表达式的日期部分
EXTRACT() 返回日期/时间的单独部分
DATE_ADD() 向日期添加指定的时间间隔
DATE_SUB() 从日期减去指定的时间间隔
DATEDIFF() 返回两个日期之间的天数
DATE_FORMAT() 用不同的格式显示日期/时间
SQL Date

SQL Date 数据类型---- MySQL 使用下列数据类型在数据库中存储日期或日期/时间值:

  • DATE - 格式:YYYY-MM-DD
  • DATETIME - 格式:YYYY-MM-DD HH:MM:SS
  • TIMESTAMP - 格式:YYYY-MM-DD HH:MM:SS
  • YEAR - 格式:YYYY 或 YY
-- 如果不涉及时间部分,那么我们可以轻松地比较两个日期!Order表中OrderDate列的数据类型是date格式
SELECT * FROM Orders WHERE OrderDate='2008-11-11';

-- 如果Order表中OrderDate列的数据类型是DATETIME 格式,下面两个语句将得不到结果,无法比较时间
SELECT * FROM Orders WHERE OrderDate='2008-11-11';  -- 如果没有时间部分,默认时间为 00:00:00。SELECT * FROM Orders WHERE OrderDate='2008-11-11 00:00:00';

-- 提示:如果您希望使查询简单且更易维护,那么请不要在日期中使用时间部分
SQL NULL 值
  1. SQL NULL 值 — NULL 值代表遗漏的未知数据。默认地,表的列可以存放 NULL 值

    如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存

    无法使用比较运算符来测试 NULL 值,比如 =、< 或 <>。我们必须使用 IS NULL 和 IS NOT NULL 操作符

 -- 仅仅选取在 "Address" 列中带有 NULL 值的记录
SELECT LastName,FirstName,Address FROM Persons WHERE Address IS NULL;
-- 仅仅选取在 "Address" 列中不带有 NULL 值的记录
SELECT LastName,FirstName,Address FROM Persons WHERE Address IS NOT NULL

​ Mysql中的IFNULL() 和 COALESCE() 函数:如果值是 NULL 则 IFNULL() 返回 0,不为NULL则返回对应值,一般用于计算式中,如下例

--如果UnitOnOrder列不为null,则返回该值,如果为null,则返回0值
SELECT ProductName,UnitPrice*(UnitsInStock+IFNULL(UnitsOnOrder,0)) FROM Products;

SELECT ProductName,UnitPrice*(UnitsInStock+COALESCE(UnitsOnOrder,0)) FROM Products;
复合select语句
-- 查询作为一个数值,放在where语句中判断
select emp_no from employees where emp_no not in (select emp_no from dept_manager);
-- 选择访问量高于平均访问量的 "site_id" 和 "count"
SELECT site_id, count FROM access_log WHERE count > (SELECT AVG(count) FROM access_log);

-- 查询select语句作为一个视图,放在from后面
-- 放在from后面: 先使用LEFT JOIN连接两张表,再从此表中选出dept_no值为NULL对应的emp_no记录
SELECT emp_no FROM (SELECT * FROM employees LEFT JOIN dept_manager ON employees.emp_no = dept_manager.emp_no) WHERE dept_no IS NULL;

SQL函数

SQL Aggregate 函数(聚合函数)

计算从列中取得的值,返回一个单一的值。可搭配group by使用, 表示按组计算值 ,有用的 Aggregate 函数:

  • AVG() - 返回平均值
  • COUNT() - 返回行数
  • FIRST() - 返回第一个记录的值
  • LAST() - 返回最后一个记录的值
  • MAX() - 返回最大值
  • MIN() - 返回最小值
  • SUM() - 返回总和
-- AVG() 函数返回数值列的平均值
    SELECT AVG(column_name) FROM table_name;

--  从 "access_log" 表的 "count" 列获取平均值,并命名为CountAverage
SELECT AVG(count) AS CountAverage FROM access_log; 
-- 选择访问量高于平均访问量的 "site_id" 和 "count"
SELECT site_id, count FROM access_log WHERE count > (SELECT AVG(count) FROM access_log);

-- COUNT() 函数返回匹配指定条件的行数。默认值可以重复
-- SQL COUNT(column_name) 语法,COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):
    SELECT COUNT(column_name) FROM table_name;
-- SQL COUNT(*) 语法,COUNT(*) 函数返回表中的记录数:
    SELECT COUNT(*) FROM table_name;
-- SQL COUNT(DISTINCT column_name) 语法,COUNT(DISTINCT column_name) 函数返回指定列的不同值的数目:
    SELECT COUNT(DISTINCT column_name) FROM table_name;

SELECT COUNT(count) AS nums FROM access_log WHERE site_id=3;  --计算 "access_log" 表中 "site_id"=3 的总访问量
SELECT COUNT(*) AS nums FROM access_log; -- 计算 "access_log" 表中总记录数
SELECT COUNT(DISTINCT site_id) AS nums FROM access_log;  -- 计算 "access_log" 表中不同 site_id 的记录数
-- 查找薪水记录超过15次的员工号emp_no以及其对应的记录次数t
select emp_no, count(emp_no) from salaries group by emp_no having count(emp_no) > 15;

-- FIRST() 函数返回指定的列中第一个记录的值,只有 MS Access 支持 FIRST() 函数
    SELECT FIRST(column_name) FROM table_name;
-- mysql中的语法,使用limit 1 来实现,升序排列取第一个
    SELECT column_name FROM table_name ORDER BY column_name ASC LIMIT 1; 

SELECT name FROM Websites ORDER BY id ASC LIMIT 1;

-- LAST() 函数返回指定的列中最后一个记录的值。只有 MS Access 支持 LAST() 函数。
    SELECT LAST(column_name) FROM table_name;
-- mysql中的语法,使用limit 1 来实现,降序排列取第一个    
SELECT column_name FROM table_name ORDER BY column_name DESC LIMIT 1;

SELECT name FROM Websites ORDER BY id DESC LIMIT 1;

-- MAX() 函数返回指定列的最大值。
    SELECT MAX(column_name) FROM table_name;
--从 "Websites" 表的 "alexa" 列获取最大值
SELECT MAX(alexa) AS max_alexa FROM Websites;

-- MIN() 函数返回指定列的最小值。
    SELECT MIN(column_name) FROM table_name;

-- SUM() 函数返回数值列的总和
SELECT SUM(column_name) FROM table_name;
-- 查找 "access_log" 表的 "count" 字段的总和
SELECT SUM(count) AS sumCount FROM access_log;

GROUP BY 语句

用于结合聚合函数,根据一个或多个列对结果集进行分组。分组之后,聚合函数计算出来的值,就是在小组内计算的值

语法:
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name;

简单应用:
 --统计 access_log 各个 site_id 的访问量
SELECT site_id, SUM(access_log.count) AS nums FROM access_log GROUP BY site_id;
-- 统计有记录的网站的记录数量
SELECT Websites.name,COUNT(access_log.aid) AS nums FROM access_log
LEFT JOIN Websites
ON access_log.site_id=Websites.id
GROUP BY Websites.name;

一般来说,分组之后,要查询出来的值,就应该是分组属性,聚合函数计算出来的值
如果查询有其他属性,那么每组只列出来一条记录,如下:

SELECT * FROM `t_book` group by author;
image-20210503220224428

HAVING 子句

在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与聚合函数一起使用。

HAVING 子句可以让我们筛选分组后的各组数据。

语法:
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value;

-- 查找总访问量大于 200 的网站
SELECT Websites.name, Websites.url, SUM(access_log.count) AS nums FROM (access_log
INNER JOIN Websites
ON access_log.site_id=Websites.id)
GROUP BY Websites.name
HAVING SUM(access_log.count) > 200;

--总访问量大于 200 的网站,并且 alexa 排名小于 200
SELECT Websites.name, SUM(access_log.count) AS nums FROM Websites
INNER JOIN access_log
ON Websites.id=access_log.site_id
WHERE Websites.alexa < 200 
GROUP BY Websites.name
HAVING SUM(access_log.count) > 200;

EXISTS 运算符

用于判断查询子句是否有记录,如果有一条或多条记录存在返回 True,否则返回 False。

语法:
SELECT column_name(s)
FROM table_name
WHERE EXISTS
(SELECT column_name FROM table_name WHERE condition);

-- 查找总访问量(count 字段)大于 200 的网站是否存在, 存在就显示出来
SELECT Websites.name, Websites.url 
FROM Websites 
WHERE EXISTS (SELECT count FROM access_log WHERE Websites.id = access_log.site_id AND count > 200);

-- EXISTS 可以与 NOT 一同使用,查找出不符合查询语句的记录
SELECT Websites.name, Websites.url 
FROM Websites 
WHERE NOT EXISTS (SELECT count FROM access_log WHERE Websites.id = access_log.site_id AND count > 200);

-- 使用含有关键字exists查找未分配具体部门的员工的所有信息。
select * from employees where not exists 
(select emp_no from dept_emp where dept_emp.emp_no = employees.emp_no)

SQL Scalar 函数

基于输入值,返回一个单一的值。有用的 Scalar 函数:

  • UCASE() - 将某个字段转换为大写
  • LCASE() - 将某个字段转换为小写
  • MID() - 从某个文本字段提取字符,MySql 中使用
  • SubString(字段,起始位置,长度) - 从某个文本字段提取字符 。 (注意:字符串的第一个字符的索引是1)
  • LEN() - 返回某个文本字段的长度
  • ROUND() - 对某个数值字段进行指定小数位数的四舍五入
  • NOW() - 返回当前的系统日期和时间
  • FORMAT() - 格式化某个字段的显示方式
-- UCASE() 函数把字段的值转换为大写。
SELECT UCASE(column_name) FROM table_name;
-- LCASE() 函数把字段的值转换为小写。
SELECT LCASE(column_name) FROM table_name;

SELECT UCASE(name) AS site_title, url FROM Websites;
SELECT LCASE(name) AS site_title, url FROM Websites;

-- MID() 函数用于从文本字段中提取字符。
SELECT MID(column_name, start[,length]) FROM table_name;
参数描述:
column_name    必需。要提取字符的字段。
start    必需。规定开始位置(起始值是 1)。
length    可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。

SELECT MID(name,1,4) AS ShortTitle FROM Websites; -- 从 "Websites" 表的 "name" 列中提取前 4 个字符

-- LEN() 函数返回文本字段中值的长度。MySQL 中函数为 LENGTH():
SELECT LENGTH(column_name) FROM table_name;

--从 "Websites" 表中选取 "name" 和 "url" 列中值的长度
SELECT name, LENGTH(url) as LengthOfURL FROM Websites;

-- ROUND() 函数用于把数值字段舍入为指定的小数位数。
SELECT ROUND(column_name,decimals) FROM table_name;
参数描述
column_name    必需。要舍入的字段。
decimals    必需。规定要返回的小数位数。

-- NOW() 函数返回当前系统的日期和时间。
SELECT NOW() FROM table_name;
-- 从 "Websites" 表中选取 name,url,及当天日期
SELECT name, url, Now() AS date FROM Websites;

-- FORMAT() 函数用于对字段的显示进行格式化。
SELECT FORMAT(column_name,format) FROM table_name;
-- 从 "Websites" 表中选取 name, url 以及格式化为 YYYY-MM-DD 的日期
SELECT name, url, DATE_FORMAT(Now(),'%Y-%m-%d') AS date
FROM Websites;

经典SQL语句

-- 查找employees里最晚入职员工的所有信息
select * from employees order by hire_date desc limit 1;  -- 可能有误,因为最晚入职时间的员工可能不止一个
select * from employees where hire_date = (select max(hire_date) from employees);
select * from employees where hire_date in (select max(hire_date) from employees);

-- 查找employees里入职员工时间排名倒数第三的员工所有信息
select * from employees 
where hire_date = (
    select distinct hire_date from employees order by hire_date desc limit 2,1
);

-- 查找所有已经分配部门的员工的last_name和first_name以及dept_no,未分配的部门的员工不显示
select employees.last_name, employees.first_name, dept_emp.dept_no from employees inner join dept_emp on employees.emp_no = dept_emp.emp_no;
select employees.last_name, employees.first_name, dept_emp.dept_no from employees, dept_emp
where employees.emp_no = dept_emp.emp_no;

-- 查找薪水记录超过15次的员工号emp_no以及其对应的记录次数t 
select emp_no, count(emp_no) as t from salaries group by emp_no having t > 15;

-- 找出所有员工具体的薪水salary列,对于相同的薪水只显示一次,并按照逆序显示
select distinct salary from salaries order by salary desc;

-- 找出所有非部门领导的员工emp_no。两种方法:
-- 使用not in 
select emp_no from employees where emp_no not in (select emp_no from dept_manager);
-- 使用join形式,效率更高
select e.emp_no from employees e left join dept_manager d on e.emp_no = d.emp_no
where dept_no is null;

-- 查找employees表所有emp_no为奇数,且last_name不为Mary的员工信息,并按照hire_date逆序排列
select * from employees where emp_no % 2 = 1 and last_name != 'Mary' order by hire_date desc

-- 获取薪水第二多的员工的emp_no以及其对应的薪水salary
select emp_no, salary from salaries order by salary desc limit 1, 1;

-- last_name和first_name拼接起来作为Name,中间以一个空格区分
select concat(last_name, " ", first_name) as Name from employees;
SELECT last_name||" "||first_name AS Name FROM employees; -- SQLite数据库只支持用连接符号"||"来连接字符串

-- 批量插入两条数据,两种方法:
insert into actor values(1, "PENELOPE", "GUINESS", "2006-02-15 12:34:33"), (2, "NICK", "WAHLBERG", "2006-02-15 12:34:33");
INSERT INTO actor SELECT 1, 'PENELOPE', 'GUINESS', '2006-02-15 12:34:33'
UNION SELECT 2, 'NICK', 'WAHLBERG', '2006-02-15 12:34:33'

-- 删除emp_no重复的记录,只保留最小的id对应的记录。 
DELETE FROM titles_test WHERE id NOT IN (SELECT MIN(id) FROM titles_test GROUP BY emp_no);
-- 上面的语句会报错,因为MySQL的UPDATE或DELETE中子查询不能为同一张表,可将查询结果再次SELECT,同时需要起别名,如下:
delete from titles_test where id not in
(select * from (select min(id) from titles_test group by emp_no) as a);

-- id=5以及emp_no=10001的行数据替换成id=5以及emp_no=10005,其他数据保持不变
--全字段更新替换。由于 REPLACE 的新记录中 id=5,与表中的主键 id=5 冲突,故会替换掉表中 id=5的记录,否则会插入一条新记录(例如新插入的记录 id = 10)。并且要将所有字段的值写出,否则将置为空
REPLACE INTO titles_test VALUES (5, 10005, 'Senior Engineer', '1986-06-26', '9999-01-01');

UPDATE titles_test SET emp_no = REPLACE(emp_no,10001,10005) WHERE id = 5;

UPDATE titles_test SET emp_no = 10005 WHERE id = 5

-- 查询,积分表里面出现三次以及三次以上的积分
select number from grade group by number having count(number) >= 3;

-- 写出一个sql语句查询每个用户最近一天登录的日子,并且按照user_id升序排序
select user_id, max(date) from login group by user_id order by user_id;

-- 查询各个岗位分数的平均数,并且按照分数降序排序,结果保留小数点后面3位(3位之后四舍五入)
select job, round(avg(score),3) as avg from grade group by job order by avg desc;

-- 查询在2025-10-15以后状态为购买成功的C++课程或者Java课程或者Python的订单,并且按照order_info的id升序排序
select * from order_info
where datediff(date,"2025-10-15")>0
    and status = "completed"
    and product_name in("C++","Java","Python")
order by id
-- DATEDIFF(d1,d2) 语句---计算日期 d1->d2 之间相隔的天数

-- 查询在2025年内投递简历的岗位和数量,并且按数量降序排序
select job, sum(num) as cnt from resume_info where year(date)='2025' group by job order by cnt desc
--查找各个部门领导薪水详情以及其对应部门编号dept_no,输出结果以salaries.emp_no升序排序,并且请注意输出结果里面dept_no列是最后一列
#由于输出顺序是按照emp_no递增来的,join时salaries表要放在前面,否则输出顺序不对
#由于两个表都有重复数据,所以两个表的to_date都要做限制
select s.emp_no, s.salary, s.from_date, s.to_date, d.dept_no from salaries s
join dept_manager d on s.emp_no = d.emp_no 
where s.to_date='9999-01-01' and d.to_date='9999-01-01'
order by s.emp_no;

-- 各个title类型对应的员工薪水对应的平均工资avg。结果给出title以及平均工资avg,并且以avg升序排序
select t.title, avg(IFNULL(s.salary, 0)) from titles t 
left join salaries s on t.emp_no = s.emp_no
group by t.title
order by avg(s.salary)

-- 三个表连接,employees/deptno_emp/deptno_name
-- 查找所有员工的last_name和first_name以及对应的dept_name,也包括暂时没有分配部门的员工

SELECT em.last_name, em.first_name, dp.dept_name
FROM (employees em LEFT JOIN dept_emp de ON em.emp_no = de.emp_no)
LEFT JOIN departments dp ON de.dept_no = dp.dept_no
-- 也可以直接去掉括号,但是要理解
SELECT em.last_name, em.first_name, dp.dept_name
FROM employees em LEFT JOIN dept_emp de ON em.emp_no = de.emp_no
LEFT JOIN departments dp ON de.dept_no = dp.dept_no
-- 也可以写复杂点
select e.last_name, e.first_name, dept.dept_name from employees e 
left join (select de.emp_no, d.dept_name from dept_emp de 
          left join departments d on de.dept_no = d.dept_no) as dept
          on e.emp_no = dept.emp_no;

-- 将所有获取奖金的员工当前的(salaries.to_date='9999-01-01')薪水增加10%       
update salaries set salary = salary * 1.1 where to_date = '9999-01-01' 
and emp_no in (select emp_no from emp_bonus)

你可能感兴趣的:(sql,学习,mysql)