赞
踩
CREATE DATABASE my_database; -- 新建数据库
CREATE DATABASE IF NOT EXISIT my_database; -- 如果数据库不存在才新建数据库
DROP DATABASE IF EXISIT my_database; -- 如果数据库存在才删除,因为重复删除会报错。
DROP DATABASE my_database; -- 删除数据库
USE my_database; -- 切换数据库
ALTER DATABASE my_database DEFAULT CHARACTER SET UTF8; -- 更改数据库的字符集
SHOW DATABASES; -- 显示所有数据库
SELECT DATABASE(); -- 显示当前选中的数据库
SHOW CREATE DATABASE my_database; -- 显示数据库的创建语句以及characterset。
我们能执行选中操作的只有数据库,所以任何命令,都需要显式地指定表名。
-- 增加一个表 CREATE TABLE t_student ( first_name VARCHAR(30), second_name VARCHAR(30), age INT ); -- 如果表不存在才增加一个表 CREATE TABLE IF NOT EXIST t_student( first_name VARCHAR(30), second_name VARCHAR(30), age INT ); -- 可以在新建表的时候就定义后约束 CREATE TABLE IF NOT EXISTS t_students( first_name VARCHAR(30), second_name VARCHAR(30), age INT, NOT NULL(first_name,second_name,age) -- 建议属性都加个NOT NULL约束比较好 ); -- 新增一个类似的表 CREATE TABLE t_newtable LIKE t_oldtable; -- 使用蠕虫复制来复制表 CREATE TABLE t_newtable LIKE t_oldtable; -- 先建好一个新的表 INSERT INTO t_newtable (属性值1,属性值2) -- 这里的属性值可以省略 SELECT 属性值1, 属性值2 -- 注意,这里的属性值可以是常量来的。就t_newtable对应的属性永远都插常量。 FROM t_oldtable; -- t_newtable后面的属性值要跟SELECT后面的属性值一对一对应才可以的。 -- 就像是普通INSERT INTO那样,只是VALUES 变成了SELECT而已。 -- 这个命令适合已经有表存在的情况,如果想新建一个表,建议用 CREATE TABLE t_newtable ( SELECT * FROM t_oldtable WHERE condition); -- 注意,跟建普通表一样,括号不能省。
ALTER TABLE t_students RENAME TO t_student; -- 修改表的命名
ALTER TABLE t_student CHARACTER SET utf8; -- 把一个表的编码改成指定编码
ALTER TABLE t_student ENGINE='InnoDB'; -- 修改表的引擎,用InnoDB就好了,支持外键和事物。
/*用 SHOW CREATE TABLE t_student 可以看到表的当前引擎*/
SHOW TABLES; -- 显示选中的数据库(use my_database)的所有表
SHOW CREATE TABLE t_student; -- 显示表的创建语句
-- 显示表的所有列与列的属性,两者一样的。
DESC t_student;
SHOW COLUMNS FROM t_student;
DROP TABLE t_student; -- 直接删除表
DROP TABLE IF EXISIT t_student; -- 如果表存在就删除表
ALTER TABLE t_student ADD score INT; -- 增加表一列 ALTER TABLE t_student CHANGE score address VARCHAR(30) NOT NULL; -- 修改一个列的名字和类型 ALTER TABLE t_student DROP scroe; -- 删除一列 --增加一个主键,可以用多个列作为联合主键 ALTER TABLE t_student ADD PRIMARY KEY [AUTO_INCREMENT] (id1 [,id2]); -- 删除主键 ALTER TABLE t_student DROP PRIMARY KEY; -- 因为主键一般只有一个,所以要删除就只需这样。 -- 但是当主键连住AUTO_INCREMENT,就不能用这种方法删除主键了。 -- 修改自增值的大小 ALTER TABLE t_student AUTO_INCREASE = 100; -- AUTO_INCREMENT 只能由两种方法设置 1、在创建表的时候就在PRIMARY KEY后面设置 2、用MODIFY把一个列设为PRIMARY KEY的时候设置(注意要先把原来的主键删除了) -- 增加一个外键列 ALTER TABLE t_student ADD CONSTRAINT fk_1 FOREIGN KEY (classroom_id) REFERENCE t_classroom (id); -- 比较少用,因为java也能做外键操作,而且性能更好。
我们能选中的只有数据库,不能选中表,所以任何对表的增删改查操作,都需要指定表名。
-- 可以只增加一部分
INSERT INTO t_student (valueName_1,valueName_2)
VALUES (value_1,value2),(value_1,value2),(value_1,value2)...;
--需要全部属性都增加,不增加的要用null
INSERT INTO t_student VALUES (value_1,value_2,value_3...);
-- 按条件删除
DELETE FROM t_student WHERE condition1 && condition2;
-- 没有条件删除,一条一条删,auto_increase值会保留
DELETE FROM t_student;
-- 销毁表格,auto_increase值不会保留
TRUNCATE TABLE t_student;
-- 按条件更改某一列的数值
UPDATE t_student SET valueName_1 = newVAl,valueName_2 = newVal
WHERE condition1 && condition2
--全部对所有数值全部改完
UPDATE t_student SET valueName_1 = newVal ,valueName_2= newVal;
--查询表所有数据 SELECT * FROM t_student; -- 查询指定列 SELECT valName_1 , valName_2 FROM t_student; -- 别名查询,加上别名方便观看和处理查询到的数据 SELECT valName_1 otherName, valName_2 anotherName FROM t_student; -- 清除重复值查询。 SELECT DISTINCT valName_1,valName_2 FROM t_student; -- 查询结果参与运算:要求参与运算的值都是整数才行 -- 某列数据与固定值运算 SELECT valName_1 + 20 FROM t_student; -- 多列数据之间运算 SELECT price * count TotalPrice FROM t_student; -- 条件查询 SELECT * FROM t_student WHERE id>3 && id<10; -- 查询后排序 SELECT * FROM t_student ORDER BY score [DESC / ASC] -- 默认是升序,ASC,降序需要设置。 -- 分页查询 SELECT * FROM t_stduent LIMIT beginIndex,pageSize; /* 分页查询分为逻辑分页和物理分页,逻辑分页就是一次过把东西都拿出来,在JAVA中模拟分页效果,内存占用比较大,但是速度就很快,物理分页就是真实地从MYSQL中拿出指定位置和长度的数据,内存占用比较低, 但是速度慢一点。 */ -- 当只需要前面几个的时候,可以用LIMIT来限制生成数据的数量 SELECT b.s_id 学号, s_name 姓名, s_birth 生日, s_sex 性别, c_name 科目, s_score 成绩 FROM t_scores a,t_students b,t_courses c WHERE a.s_id = b.s_id && c.c_id = a.c_id ORDER BY a.s_score DESC LIMIT 5;
-- 创建用户名
CREATE USER 'username'@'主机名' IDENTIFIED BY '密码';
-- 删除用户
DROP USER 'username'@'主机名'
-- 给用户赋予权限
GRANT 权限1,权限2,权限3,权限4 ON database_name.table_name TO 'username'@'主机名'
-- 收回用户的权限
REVOKE 权限1,权限2,权限3 ON database_name.table_name FROM 'username'@'主机名'
-- 查看权限
SHOW GRANTS FOR 'username'@'主机名'
-- 修改普通用户密码:
(登录有权限的用户状态下)SET PASSWORD FOR 'username'@'主机名'='new password';
-- 修改管理员密码:
(不必登录)mysqladmin -uroot -p password; -- 然后按照提示操作即可
在WHERE后面可以放这些语句:
-- BETWEEN ... AND... 不同数据库处理方式不一样,MySQL是左右都是闭区间 SELECT * FROM t_student WHERE score BETWEEN 80 AND 100; -- 当然也可以配合NOT来使用 -- IN运算符:查询列的值是否在指定的集合中。精确查找指定的。 SELECT * FROM t_student WHERE id IN (1,4,5,10); -- 空值判断: IS NULL SELECT * FROM t_stdent WHERE score IS NULL; -- 查找成绩为空的人。 -- 模糊查询:LIKE,只有LIKE条件才能用通配符!等号或者不等号不能用通配符 SELECT * FROM t_student WHERE name LIKE '王_%'; -- 其中'_'表示一个任意字符, -- '%'表示0个或多个任意字符, -- 住址不包含'lon'三个字母的人,这时不能用'!'来表示取反了 SELECT * FROM Persons WHERE City NOT LIKE '%lon%' -- 经典的判断 SELECT * FROM t_student WHERE score >= 80 && name LIKE '王_%' OR id IN (2,4,6);
还有一些常用的比较运算符:
符号 | 含义 |
---|---|
= | 等于 |
> | 大于 |
>= | 大于或等于 |
< | 小于 |
<= | 小于或等于 |
!= | 不等于 |
数据库也是可以用函数的,叫聚合函数,常用的聚合函数如下:
-- 把一些属性连接成字符串返回 SELECT CONCAT(productName,'的售价为:',salePrice*cutoff) detail FROM table_name COUNT(*); --统计计算最大值 COUNT(val_name); -- 统计某列的行数,不包括null值。 COUNT(DISTINCT val_name); --统计某列不重复的行数。 MIN(val_name);--统计计算最小值 MAX(val_name);-- 统计计算最大值 SUM(val_name);-- 统计计算求和 AVG(val_name);-- 统计计算求平均 GROUPCONCAT(val_name); -- 把表的值聚合成一条数据 FIRST(val_name); -- 返回第一个值,可以配合ORDER BY来获取值。 LAST(val_name); --返回最后一个值,也可以配合ORDER BY -- 这两个方法跟MAX那些不同的地方就是,ORDER是可以考虑很多前提的,而MAX则只能处理1个列。 SELECT AVG(val_name) FROM table_name; SELECT COUNT(*) FROM table_name; -- 在JAVA中必须用long来接受结果。 SELECT SUM(val_name) FROM table_name WHERE dir_id IN(2,3); -- 这些函数都是返回一个数值,除了放在SELECT后面获得返回的表,还可以直接用来做HAVING后面做比较的,用来跟其他数据比较的: -- 找到订单总价小于2000的客户。 SELECT Customer,SUM(OrderPrice) FROM Orders GROUP BY Customer HAVING SUM(OrderPrice)<2000 -- 因为聚合函数不能放在WHERE后面,所以当聚合函数作为条件时,就要用到HAVING代替。HAVING是专门用来处理GROUP BY分裂出来的表的。 -- 找客户 "Bush" 或 "Adams" 拥有超过 1500 的订单总金额。 SELECT Customer,SUM(OrderPrice) FROM Orders WHERE Customer='Bush' OR Customer='Adams' GROUP BY Customer HAVING SUM(OrderPrice)>1500 -- 要注意跟VIEW区分开,VIEW是放在FROM后面的。
SELECT
**后面跟了一个这种聚合函数,表中的所有记录就会马上塌陷成一行。如果有GROUP BY
则会塌陷成好几个表。GROUP BY
就是把一个表先分裂成几个表,就特别适合跟这些聚合函数在一起使用,聚合函数把一个表塌陷了,还是有好几个数据**(因为GROUP BY
会把表分开的)**GROUP BY
在把表分裂成几个以后,即使没有聚合函数,也是会把表塌陷成几个表的。HAVING COUNT(id)
获得某个分裂表的数量AVG()
函数如果只有null值,则返回null,否则像其他所有聚合函数一样,忽略null值WHERE
后面不能使用聚合函数的!聚合函数只能用在两个地方,SELECT
后面和HAVING
后面group by
分裂出来的表
COUNT(id)
是只计算分裂表中的id数,SUM(score)
是只计算分列表中的每一条score的总和SUM(CASE WHEN)
是只对分裂表中的对应列每一条记录进行转换然后求最大值。像CREATE ,ALTER ,DROP , RENAME ,SHOW 这种既能对database操作,又能对table进行操作的关键字,就统一需要加上DATABASE 或者 TABLE
像 SELECT , INSERT INTO , DELETE FROM , UPDATE 这种只能作用在table的命令行,就不需要加上TABLE或者DATABASE。
INT(10) 的意思是数字最多有10位,**VARCHAR(20)**表示最多有20个字符。
DATE是yyyy-mm-dd 的格式,DATE是要加单引号的,在SQL中除了整数、小数以外,其他类型数字都要加上单引号。
用飘号:` 包住的关键字,会失去关键字的效果,变成普通的单词。
想跨数据库访问表,应该用如下格式:otherDB.otherTable 其他库+.+其他表。
不要在数据库中放入时间,只放入日期,那么就可以用日期进行各种比较。一涉及时间数据库就蒙圈了。
当一个表包含了另外两个表的主键,那么可以用联合主键来代替自己维护一个主键。比如:
CREATE TABLE t_students ( -- 学生表格 s_id varchar(20) PRIMARY KEY, s_name varchar(20) DEFAULT '', s_birth date DEFAULT '1990-09-20', s_sex varchar(10) DEFAULT '', ); CREATE TABLE t_coureses( --课程表格 c_id VARCHAR(20) PRIMARY KEY, c_name VARCHAR(20) DEFAULT '' NOT NULL, t_id VARCHAR(20) NOT NULL ); CREATE TABLE t_scores( -- 成绩表格 s_id VARCHAR(20) , -- 学生编号 c_id VARCHAR(20) , -- 课程编号 s_score DECIMAL NOT NULL, -- 分数 PRIMARY KEY (s_id,c_id) ); -- 成绩表格可以用学生表格和课程表格作为主键,只有两个主键都一样,才认为是同一条成绩数据。这样可以省下一个主键位。
但是要注意:联合主键的定义方式只能像上面代码那样定义,如果逐个定义主键,会报错诶。
另外,因为一个表只能有一个主键,所以不用为主键起名也可以用语句正常增加和删除主键,算式一个小语法糖啦
-- 下面这句话 SELECT * FROM t_student ts WHERE condition_1 GROUP BY ts_valName HAVING condition_2 ORDER BY valName_1 DESC LIMIT beginIndex , pageSize; -- 执行的真正顺序是: 1. FROM t_student ts 2. WHERE condition_1 3. GROUP BY ts_valueName 4. SELECT * 5. HAVING condition_2 6. ORDER BY val_name DESC 7. LIMIT beginIndex , pageSize; -- 所以在Where的时候就能用到table的别名,但是不能用select中定义的别名。 -- where后面不能定义别名。HAVING 后面也不能定义别名,但是HAVING可以用SELECT定义的别名
清除重复查询时,当有多个字段名,要求指定的字段都一样才算是重复的。
应该把筛选最多的条件放到WHERE前面,可以提高点性能
类型 | 占用空间 | 存储范围 |
---|---|---|
TINYINT | 1字节 | -128~127 |
SMALLINT | 2字节 | -32768~32767 |
MEDIUMINT | 3字节 | -800万到800万 |
INT | 4字节 | -21亿~21亿 |
BIGINT | 8字节 | 超大的 |
FLOAT | 4字节 | 不精确 |
DOUBLE | 8字节 | 不精确 |
DECIMAL | 8字节 | 精确 |
CHAR(M) | ||
VARCHAR(M) | ||
DATE | 3字节 | yyyy-mm-dd格式 |
DATETIME | 8字节 | YYYY-MM-DD HH:MM:SS格式 |
约束可以直接接到类型后面。但建议PRIMARY KEY
和FROEIGN KEY
还是另外放在后面。
NOT NULL
非空约束,如果传入null值会报错,一般值最好还是加个非空约束,对运行速度有提升的;
UNIQUE
唯一约束,该列的内容必须唯一。
增加**PRIMARY KEY
这个约束会送你一个NOT NULL
和UNIQUE
,无论是建表时期还是后来加**的。
PRIMARY KEY
最好只用来约束数值类型,而且加上**AUTO_INCREASE
。系统并不会自动变成AUTO_INCREASE
** 的!还是要自己设置。只有PRIMARY KEY
才有资格加上AUTO_INCREASE
AUTO_INCREASE
只要不赋值或者赋值为null,就会从1开始,步长为1,不能与DEFAULT共用。
**AUTO_INCREASE
这个约束只能加在INT等数值后面,而且DEFAULT
只能是NULL
否则会报错。如果给AUTO_INCREASE
**的主键赋值为null
,系统会自动计算新的主键值。
如果没有特别定义约束的话,是啥约束都没有的,没有NOT NULL
,没有定义DEFAULT
,也没有UNIQUE
的。每次MODIFY或者CHANGE都要重新定义约束,但MODIFY不会删除PRIMARY KEY约束。
NULL值是不能进行**>=、!=、<=** 那些逻辑判断的,他只能接受 IS NULL
和 IS NOT NULL
这两种判断。
NULL值也是不能参与四则运算的,可以用MySQL的**IFNULL(val_name,0)
**来定义如果值为null时,用来计算的默认值
DEFAULT XX
默认值约束,当不传入数据,就会用这个默认值,不能给有AUTO_INCREASE
的PRIMARY KEY
设置默认值。
NOT NULL 只能在建表的时候就定义好的,想追加或者删除只能用MODIFY了,不能用ALTER TABLE ADD
那个的。
UNIQUE 和 DEFAULT 都可以。在建表以后追加和删除:
-- 向已存在的表定义新增default值 ALTER TABLE Persons ALTER City SET DEFAULT 'SANDNES'; -- 把已经定好的default值删掉 ALTER TABLE Persons ALTER City DROP DEFAULT; -- 向已存在的表追加UNIQUE ALTER TABLE Persons ADD UNIQUE (name); -- 给UNIQUE约束起个名可以方便删除UNQIE约束 ALTER TABLE Persons ADD CONSTRAINT uc_PersonID UNIQUE (Id_P,LastName); -- 删除UNIQUE约束 ALTER TABLE Persons DROP INDEX uc_PersonID; --注意是INDEX而不是UNQUE
所有约束都可以通过ADD,MODIFY,CHANGE等方式来重置和定义,上面所述的只是多一个快捷一点的方式而已。
当PRIMARY KEY
跟AUTO_INCREMENT
一起用,则不能直接通过DROP
删除PRIMARY KEY
了,要先用MODIFY
把AUTO_INCREMENT
去掉(MODIFY不能去掉PRIMARY KEY),再DROP PRIMARY KEY
外键格式有点复杂,只能记住吧:
-- 在建表时期增加一个外键 CREATE TABLE Employee( id INT, name VARCHAR(20), dep_id INT, PRIMARY KEY AUTO_INCREASE (id), CONSTRAINT E_d_D_id_fk -- 注意,要在定义好外键的列之后,再声明外键约束! FOREIGN KEY (dep_id) REFERENCES Department (id) --要注意从表的属性列也要用括号包住的! ); -- 当建好表以后,对表添加外键指向另一个表 ALTER TABLE Employee ADD CONSTRAINT employee_dep_id_to_department_id_fk FOREIGN KEY (dep_id) REFERENCES Department(id); -- 删除外键约束 ALTER TABLE Employee DROP FOREIGN KEY E_d_D_id_fk;
如果想关联的列跟随着主键更新或者删除,应该在定义的时候加上ON DELETE CASCADE
以及ON UPDATE CASCADE
-- 创建带有级联更新外键的表完整写法 CREATE TABLE Employee( id INT, name VARCHAR(20), dep_id INT, PRIMARY KEY AUTO_INCREASE (id), CONSTRAINT E_d_D_id_fk FOREIGN KEY (dep_id) REFERENCES Department (id) --要注意主从表的属性列也要用括号包住的! ON DELETE CASCADE ON UPDATE CASCADE ); -- 添加级联更新的外键完整写法 ALTER TABLE Employee ADD CONSTRAINT E_d_D_id_fk FOREIGN KEY (dep_id) REFERENCES Department (id) ON DELETE CASCADE ON UPDATE CASCADE
但是要知道,级联操作好像很叼,但是他运行效率比java低很多,尽量不要在数据库中进行各种运算操作。
外键只能是主表的主键或者空。
当多表查询时,就会有笛卡尔积,因为两个表相交的话,会导致表之间的记录相乘。所以才要有不会重复的主键,方便多表查询时可以找到对应的记录。
-- 多表查询,有多少个表,就至少要有n-1个链接
SELECT p.id,p.productName,pd.dirName,ps.storeNum,p.salePrice,p.salePrice*ps.storeNum 利润
FROM product p,productdir pd,productstock ps -- FROM中可以声明表的别名,可以让SELECT用。
WHERE p.dir_id=pd.id AND p.id=ps.product_id -- 用链接消除笛卡尔积
ORDER BY 利润 DESC; -- 这里可以用别名了
-- 但是这种叫隐式连接,已经逐渐被淘汰了,以后都用JOIN...ON ...这种形式的显示连接了
SELECT p.id,p.productName,pd.dirName,ps.storeNum,p.salePrice,p.salePrice*ps.storeNum 利润
FROM product p
JOIN productdir pd ON p.dir_id = pd.id -- 显式连接
JOIN productstock ps ON ps.product_id = p.id -- 显示连接
ORDER BY 利润 DESC;
上面是**JOIN…ON…的形式,他是INNER JOIN … ON…**的简化版,就用简化版好了。
当有表格Persons
id_p | 姓名 |
---|---|
1 | 张三 |
2 | 李四 |
3 | 王五 |
还有表格Orders
id_o | 订单号 | id_p |
---|---|---|
1 | 订单_1 | 1 |
2 | 订单_2 | 2 |
3 | 订单_3 | 65 |
如果只是用JOIN,而不用ON的时候,会返回如下结果
Persons.id_p | id_o | 姓名 | 订单号 | Orders.id_p |
---|---|---|---|---|
1 | 1 | 张三 | 订单_1 | 1 |
1 | 2 | 张三 | 订单_2 | 2 |
1 | 3 | 张三 | 订单_3 | 65 |
2 | 1 | 李四 | 订单_1 | 1 |
2 | 2 | 李四 | 订单_2 | 2 |
2 | 3 | 李四 | 订单_3 | 65 |
3 | 1 | 王五 | 订单_1 | 1 |
3 | 2 | 王五 | 订单_2 | 2 |
3 | 3 | 王五 | 订单_3 | 65 |
当用了ON以后,就会按照要求,把Persons.id_p和Orders.id_p相同的筛选出来,也就是标红的两条记录。
如果用普通JOIN,则只返回匹配到的,也就是这两条标红的。
如果用LEFT JOIN,就会把JOIN左边的表,无论是否有匹配到,全部都返回,**如果没有匹配到,那值对应的值就是null。**非常强势
Persons.id_p | id_o | 姓名 | 订单号 | Orders.id_p |
---|---|---|---|---|
1 | 1 | 张三 | 订单_1 | 1 |
2 | 2 | 李四 | 订单_2 | 2 |
3 | null | 王五 | null | null |
RIGHT JOIN同理的。注意,JOIN右边的列表,永远是RIGHT。
还有一个两个都强势的:FULL JOIN,两个都返回了再说,没有匹配就用null,有匹配才填信息。
UNION / UNION ALL是用来把两个查询的结果合并的,他要求两次查询的结果,列数相等,类型相似。
SELECT val_name(s) FROM table_1
UNION ALL -- UNION 和 UNION ALL 的区别就是是否会保留相同的记录,UNION ALL会保留相同的记录的。
SELECT val_name(s) FROM table_2;
UNION本来是被设计用来组合两个不同的表的,但是他的效率比OR高,所以即使我们是对同一个表操作,也可以使用UNION来代替OR!
获得的记录,属性名会由UNION前面的语句来定义
SQL判断是否相同的逻辑是:所有列的元素都相同,才认为两条记录相同。
在INSERT INTO table_2 (a,b,c) SELECT a , b ,c FROM table_1;
之前,我们总是要新建一个表:CREATE TABLE table_2 LIKE table_1
,显得有点麻烦了。而SELECT INTO
就是用来处理没有表的情况。
但是MySQL不支持SELECT INTO命令!他有代替的命令:
-- 把table_1选中的列插入table_2中
CREATE TABLE Persons_orders_backup(
SELECT p.id_p 客户id,p.name 客户姓名,p.city 城市,o.order_num 订单号码
FROM Persons p
JOIN Orders o ON p.id_p = o.id_p); -- 是可以用JOIN的!
-- 因为新的表啥信息都没有,所以会以SELECT后面指定的属性值作为列
CREATE SELECT
要求table_2不存在,所以在已经存在一个table_2,只是想用另外的表扩充下的情况他是处理不了的。
但是用来作为快速备份,或者把查询的结果保存成一个新的表格,是非常有用的!跟INSERT INTO SELECT
各有优势。
数据库里是没有变量保存值这种概念的,视图是你保存数据的唯一方式了。
-- 新建一个视图 CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition; -- 当新建了一个视图之后,就可以把它看成一张表了,MySQL每次用到这个视图,都会重新查询一次,保证数据是最新的 -- 新建好以后就可以使用视图,就当是普通表来用就好。 SELECT * FROM view_name; -- 更新一个视图,表示用同一个视图名,但是视图里面的内容就不同了 CREATE OR REPLACE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition; -- 删除视图 DROP VIEW view_name;
虽然JAVA也能做,但是知道一下SQL里是如何操作时间的也是不错的,但是SQL处理时间就很尴尬,一般都是用来处理日期:
一些关于时间的方法
函数 | 描述 |
---|---|
NOW() | 返回当前的日期和时间 |
CURDATE() | 返回当前的日期 |
CURTIME() | 返回当前的时间 |
DATE() | 提取日期或日期/时间表达式的日期部分 |
EXTRACT() | 返回日期/时间按的单独部分 |
DATE_ADD() | 给日期添加指定的时间间隔 |
DATE_SUB() | 从日期减去指定的时间间隔 |
DATEDIFF() | 返回两个日期之间的天数 |
DATE_FORMAT() | 用不同的格式显示日期/时间 |
-- GROUP BY的常规用法
SELECT Customer,SUM(OrderPrice)
FROM Orders
GROUP BY Customer
-- 可以看做GROUP BY按照列,把一个表分成好几个表,然后SELECT 对每一个表执行操作以后,再把所有表结合成一个表。有点像java 中stream流的toMap方法。
所谓子查询,就是让一个查询结果成为另一个查询的一部分:
-- 找到成绩比平均分高的学生
SELECT *
FROM t_student
WHERE s_score > (SELECT AVG(s_score) FROM t_student);
注意,子查询语句一定要放在小括号中的,否则程序会报错。
数据库查询的步骤是先查询出子查询的结果,再将子查询结果作为父查询的一部分执行父查询。
子查询一共会有3种情况:
单行单列:可以用作 >、<、=、!=、>=、<=的比较条件(案例同上)。
多行单列:可以放在IN
或者NOT IN
后面作为条件
-- 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
select stu_b.s_id 学号, avg(sco_b.s_score) 平均分
from t_students stu_b
join t_scores sco_b on sco_b.s_id = stu_b.s_id and stu_b.s_id in (
select stu.s_id
from t_students stu
left join t_scores sco on sco.s_id = stu.s_id and sco.s_score < 60
group by stu.s_name
having COUNT(*) >= 2
)
group by stu_b.s_name;
多行多列:可以放在FROM
或者JOIN
后面。暂时找不到比较好的案例。
这部分参考了璀璨小二的博客
CASE WHEN THEN ELSE END
这个语法对数据库操作太重要了,他有两种写法:
-- 简单CASE函数
CASE sex
WHEN 1 THEN '男'
WHEN 2 THEN '女'
ELSE '其他' END
-- CASE搜索函数
CASE
WHEN sex=1 THEN '男'
WHEN sex=2 THEN '女'
ELSE '其他' END
CASE函数其实可以看成一个普通列,只是他会逐条改变这个列的内容,所以这个函数可以放在SELECT、HAVING、WHERE、聚合函数参数这些地方。
他最后会把这个列的值变成THEN 后面的类型。
-- 按照人口统计人数
SELECT country,
SUM( CASE WHEN sex = '1' THEN
population ELSE 0 END), --男性人口
SUM( CASE WHEN sex = '2' THEN
population ELSE 0 END) --女性人口
FROM Table_A
GROUP BY country;
-- 这样就可以一个select统计两个数,不用JOIN
所以有了case以后,就再也不用为了一个数值就JOIN一个新的表了!
可以作为检查条件,又不会阻挡其他数据的输入
-- 要求如果是女员工,那个工资就要比1000高
CONSTRAINT check_salary CHECK
(CASE WHEN sex = '2'
THEN CASE WHEN salary > 1000
THEN 1 ELSE 0 END
ELSE 1 END = 1 )
/*
工资5000以上的职员,工资减少10%
工资在2000到4600之间的职员,工资增加15%
很容易考虑的是选择执行两次UPDATE语句,如下所示
*/
UPDATE Personnel
SET salary = CASE WHEN salary >= 5000
THEN salary * 0.9
WHEN salary >= 2000 AND salary < 4600
THEN salary * 1.15
ELSE salary END;
假设有学生表如下:
c_id | main_flag | s_id |
---|---|---|
1 | y | 100 |
2 | n | 100 |
2 | n | 200 |
3 | y | 200 |
4 | n | 200 |
4 | n | 300 |
5 | n | 400 |
6 | n | 500 |
/*
只选修一门课程的人,返回那门课程的ID
选修多门课程的人,返回所选的主课程ID
*/
select *,case
when count(stu.c_id) =1
then max(stu.c_id)
else max(case stu.main_flag
when 'y' then stu.c_id
else null end )
end 主修课程ID
from Students stu
group by stu.s_id;
-- 查询没学过"张三"老师授课的同学的信息 SELECT * FROM t_students WHERE s_id NOT IN ( SELECT stu_a.`s_id` FROM t_students stu_a JOIN t_scores sco ON sco.`s_id`=stu_a.`s_id` JOIN t_courses cou ON sco.`c_id`=cou.`c_id` JOIN t_teachers tea ON cou.`t_id`=tea.`t_id` AND tea.`t_name`='张三' ); -- 10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息 SELECT * FROM t_students WHERE s_id IN (SELECT s_id FROM t_scores WHERE c_id='01') AND s_id NOT IN(SELECT s_id FROM t_scores WHERE c_id='02');
-- 查询"01"课程比"02"课程成绩高的学生的信息及课程分数
SELECT a.* ,b.s_score 01_score,c.s_score 02_score
FROM t_students a
JOIN t_scores b ON a.s_id=b.s_id AND b.c_id='01'
LEFT JOIN t_scores c ON a.s_id=c.s_id AND c.c_id='02'
WHERE b.s_score>c.s_score;
-- 查询没有学全所有课程的同学的信息
SELECT *
FROM t_students
WHERE s_id NOT IN(
SELECT stu.s_id
FROM t_students stu
JOIN t_scores sco ON stu.`s_id`=sco.`s_id`
GROUP BY stu.`s_id`
HAVING COUNT(DISTINCT sco.`c_id`)=(SELECT COUNT(c_id) FROM t_courses)
);
-- 注意,只有SELECT 后面跟单个聚合函数,才能比较,跟c_id那种属性名,或者多个聚合函数,是会报错的
-- 17、按平均成绩从高到低显示所有学生的所有课程的成绩以及平均成绩
select stu_b.s_name 学生姓名,sco_b.s_score,ss.平均成绩 平均成绩
from t_students stu_b
left join t_scores sco_b on sco_b.s_id=stu_b.s_id
left join (select avg(sco.s_score) 平均成绩,stu.s_id student_id
from t_students stu
join t_scores sco on stu.s_id = sco.s_id
group by stu.s_name) ss on sco_b.s_id=ss.student_id
order by sco_b.s_score desc ;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。