2017/10/31 逻辑模型到->用SQL实现数据库
1:1两个人表中的主键都可以做外键
1:n在多的实体表中新增一个字段,该字段是“一”实体表的主键
m:n拆成两个1:n的关系
pk primary 主键
fk foreign 外键
---------------------------------------------------------------------
在student表中,增添两个限制:
1.not null 非空限制
2.primary key 主键限制
==================================================================+++
实例-创建主键和外键:
sql> create database yang_test;
mysql> use yang_test;
创建学生表:
mysql> create table student(s_id int not null primary key,name varchar(20),gender varchar(20),age int,address varchar(50));
创建教师表:
create table teachers(name varchar(20) not null primary key,
gender varchar(20),rank varchar(20));
创建教材表:
create table textbook(ISBN varchar(20) not null primary key,name varchar(20),author varchar(20),publisher varchar(20));
注:textbook 教材
创建课程表:
create table courses(
c_id int not null primary key,
name varchar(20),
credit int,
instructor varchar(20),
ISBN varchar(20),
foreign key(instructor) references teachers(name),
foreign key(ISBN) references textbook(ISBN));
注:instructor授课教师名、credit学分、references关联
外键属性的内容a,一定要先出现在 teachers 表中 中
创建注册表:
create table registration(
s_id int not null,
c_id int not null,
term varchar(20),
grade decimal(4,1),
primary key(s_id,c_id),
foreign key(s_id) references student(s_id),
foreign key(c_id) references courses(c_id));
mysql> show tables;
+---------------------+
| Tables_in_yang_test |
+---------------------+
| courses |
| registration |
| student |
| teachers |
| textbook |
==================================================================+++
向表中插入信息:
insert into student values (1,'Ann','F',21,'Beijing');
insert into textbook values('00000','Intro to SQL','Yang','renmin press');
insert into teachers values('Yang','F','Instructor');
insert into courses values(1,'Databases',3,'Yang','00000');
insert into registration values(1,1,201711,93.0);
=====================================================================
错误演示与总结:
(1)
关于 学生表students 中的 not null
mysql> insert into student values (null,'bob','F',22,'shanghai');
ERROR 1048 (23000): Column 's_id' cannot be null
总结1:sql中空是 null ,不能省略不写,也不能写成' '
(2)
总结2:查询关于空值信息的语句(用is,is not不用==,!=):
select * from student where address is null;
select * from student where address is not null;
(3)
学生表的学号已经设置为主键,如果出现两个学号2,那么第二个学生的信息输入将提示错误
(4)
在courses表中,有两个外键teachers 和 textbook:
foreign key(instructor) references teachers(name),
foreign key(ISBN) references textbook(ISBN));
和其他的表进行关联,当向courses中插入数据时,直接输入教师名和教材名,会提示错误。教师名和教材名在教师表和教材表中分别为主键,必须在教师表和教材表中出现相应的信息记录,才能在课程表courses中添加对应的信息。
总结为,必须先有对应的老师、教材,才能添加到课程表中的老师记录或教材记录,插入数据时,先插入主键记录,后插入外键记录;
删除数据时,先删除外键记录,后删除主键记录。
insert into textbook values('10000','intro to python','gdio','beijing press');
insert into teachers values('wei','M','Instructor');
insert into courses values(2,'python',4,'wei','10000');
=====================================================================
思考题:
插入以下信息,查询student表中地址为空 和 不为空的学生的信息
insert into student values (2,'bob','F',23,null);
mysql> select * from student where address is null;
+------+------+--------+------+---------+
| s_id | name | gender | age | address |
+------+------+--------+------+---------+
| 2 | bob | F | 23 | NULL |
+------+------+--------+------+---------+
mysql> select * from student where address is not null;
+------+------+--------+------+---------+
| s_id | name | gender | age | address |
+------+------+--------+------+---------+
| 1 | Ann | F | 21 | Beijing |
+------+------+--------+------+---------+
====================================================================
高级SQL:
create table orders(o_id int not null,o_name varchar(50),data datetime,c_id int,amount decimal(10,2));
insert into orders values
(100,'computer','2011-11-1 12:34:56',1,8800);
insert into orders values
(101,'iphone','2011-10-10 15:20:56',3,6600),
(102,'microphone','2017-09-10 09:34:56',4,450),
(102,'ipad','2014-02-27 18:24:17',4,9200),
(103,'iwatch','2017-09-13 10:34:22',2,5700),
(105,'mouse','2012-06-23 09:44:33',5,200),
(106,'pen','2013-03-31 21:34:23',6,300),
(107,'iphone','2016-04-23 07:19:22',7,7800),
(108,'ipad','2016-02-12 20:20:20',5,12000);
mysql> select * from orders;
+------+------------+---------------------+------+----------+
| o_id | o_name | data | c_id | amount |
+------+------------+---------------------+------+----------+
| 100 | computer | 2011-11-01 12:34:56 | 1 | 8800.00 |
| 101 | iphone | 2011-10-10 15:20:56 | 3 | 6600.00 |
| 102 | microphone | 2017-09-10 09:34:56 | 4 | 450.00 |
| 102 | ipad | 2014-02-27 18:24:17 | 4 | 9200.00 |
| 103 | iwatch | 2017-09-13 10:34:22 | 2 | 5700.00 |
| 105 | mouse | 2012-06-23 09:44:33 | 5 | 200.00 |
| 106 | pen | 2013-03-31 21:34:23 | 6 | 300.00 |
| 107 | iphone | 2016-04-23 07:19:22 | 7 | 7800.00 |
| 108 | ipad | 2016-02-12 20:20:20 | 5 | 12000.00 |
+------+------------+---------------------+------+----------+
mysql> select * from customers;
+------+----------+------+-----------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+------+----------+------+-----------+----------+
| 2 | li | 30 | beijing | 2645.00 |
| 3 | jeremy | 20 | shanghai | 2300.00 |
| 4 | Bob | 25 | beijing | 8596.25 |
| 5 | aaa | 25 | beijing | 8596.25 |
| 6 | bbb | 25 | beijing | 8596.25 |
| 7 | ccc | 27 | beijing | 8596.25 |
| 8 | xioayu | 24 | shenzhen | 60000.00 |
| 9 | xiaohu | 25 | guangzhou | 60000.00 |
| 1 | Ann | 22 | zhuhai | 30000.00 |
| 10 | xiaoming | 25 | beijing | 2000.00 |
+------+----------+------+-----------+----------+
1.joins-链接查询:
利用两个表中共同含有的列的相同值来链接
select列名 from 第一个表,第二个表 where 第一个表.列名 = 第二个表.列名;
实例-夺标链接查询-实质joins:
mysql> select id,name,salary,o_name,amount from customers,orders where customers.id = orders.c_id;
+------+--------+----------+------------+----------+
| id | name | salary | o_name | amount |
+------+--------+----------+------------+----------+
| 1 | Ann | 30000.00 | computer | 8800.00 |
| 3 | jeremy | 2300.00 | iphone | 6600.00 |
| 4 | Bob | 8596.25 | microphone | 450.00 |
| 4 | Bob | 8596.25 | ipad | 9200.00 |
| 2 | li | 2645.00 | iwatch | 5700.00 |
| 5 | aaa | 8596.25 | mouse | 200.00 |
| 6 | bbb | 8596.25 | pen | 300.00 |
| 7 | ccc | 8596.25 | iphone | 7800.00 |
| 5 | aaa | 8596.25 | ipad | 12000.00 |
+------+--------+----------+------------+----------+
练习:
打印顾客消费额度超过其工资的人员名单和工资信息以及消费额度
提示:select from where () and ()
mysql> select name,salary,amount from customers,orders where (orders.c_id = customers.id) and (orders.amount > customers.salary);
+--------+---------+----------+
| name | salary | amount |
+--------+---------+----------+
| jeremy | 2300.00 | 6600.00 |
| Bob | 8596.25 | 9200.00 |
| li | 2645.00 | 5700.00 |
| aaa | 8596.25 | 12000.00 |
+--------+---------+----------+
====================================================================
2.子查询-嵌入到另一个select语句中的select语句中:
select 列名或者表达式 from 表名 where 表达式 比较操作符 {all|any}(子查询语句);
(1)返回单值的子查询(=)
select * from customers where customers.id =
(select c_id from orders where o_id = 100);
orders表o_id = 100 -> orders表o_id c_id -> customers表id ->customers表信息
实例:
mysql> select * from customers where customers.id =
-> (select c_id from orders where o_id = 100);
+------+------+------+---------+----------+
| ID | NAME | AGE | ADDRESS | SALARY |
+------+------+------+---------+----------+
| 1 | Ann | 22 | zhuhai | 30000.00 |
+------+------+------+---------+----------+
1 row in set (0.00 sec)
单值子查询等效语句(重命名customers as c,):
select c.id,c.name,c.age,c.address,c.salary from customers as c,orders as o where c.id = orders.c_id and orders.o_id = 100; #@@@@@@@@@@@@@@@@@@@
(2)返回多值的子查询(in)
实例:
select * from customers where customers.id = 1;
select * from customers where customers.id in (1,2,3);
select * from customers where customers.id in (select c_id from orders where amount > 5000);
练习:
选出顾客的消费大于2000元,同时地址是北京或者上海???
select * from customers where customers.id in (select c_id from orders where amount > 2000) and address in ('beijng','shanghai');
选出消费最少的顾客信息???
提示:单值的子查询,min(...)
错解:
select * from customers where customers.id = (select c_id from orders where) and (select min(amount) from orders);
正解:
select * from customers where customers.id = (select c_id from orders where amount = (select min(amount) from orders));
选出工资最少的顾客信息(注意这里是顾客的所有信息,不仅仅是选出薪资信息)?
select * from customers where salary = (select min(salary)from customers);
(3)all,any和子查询:#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
all:所有的
any:其中之一的,任选其一
select * from customers where age > any(24,25,27);
select * from customers where age > all(24,25,27);
(4)insert语句嵌套子查询:
insert into 表名 [列名1,列名2,...,列名n] values (value1,value2,...,valueN);
insert into 表名 [列名1,列名2,...,列名n] select [列名1,列名2,...,列名n] from 表名 [where 条件];
create table customers_1(
id int,
name varchar(20),
age int,
address char(25),
salary decimal(18,2));
使用嵌套查询将消费额度大于8000元的客户的全部信息 存放在新生成的customers_1表中:
insert into customers_1 select * from customers where id in (select c_id from orders where amount > 8000)
注意:这里的 in 相当于python中的for i in range(1,10),是迭代的,会将后面所有的数据传递给前面,而不是只做in的判断。
(5)update语句嵌套子查询:
update 表名 set 列名 = 新的值 where 列名 操作符 (select 列名 from 表名 [where 条件]);
update customers set salary = salary * 1.5 where age in (select age from customers_1 where age >= 25);
注意: where a in b, b是一个数据集合,其中的所有数据都将传给a做匹配
练习:
1.将customers表中工资小于所有顾客的平均消费的人的工资提高一倍
提示:update嵌套select子查询,聚合函数avg
2.将customers表中的新数据,按照工资由大到小排列
3.求出customers表中各个城市的人的平均工资
4.求出customers表中 消费额度大于 全体顾客的平均工资 这样的顾客的全部信息
提示:select嵌套select子查询
5.列出工资高于平均消费额的客户额的客户的总个数
提示:select嵌套select子查询,聚合函数count(*)
1.将customers表中工资小于所有顾客的平均消费的人的工资提高一倍
我自己的解法-错误:
update customers set salary = salary * 2 where (customers.id in orders.c_id) and (salary < select avg(amount) from orders);
正解:
update customers set salary = salary * 2 where customers.id in (select c_id from orders group by c_id having customers.salary < avg(amount));
2.将customers表中的新数据,按照工资由大到小排列
select * from customers order by salary desc;
3.求出customers表中各个城市的人的平均工资
select avg(salary),address from customers group by address;
4.求出customers表中 消费额度大于 全体顾客的平均工资 这样的顾客的全部信息
select * from customers where customers.id in (select c_id from orders where amount > (select avg(salary) from customers));
5.列出工资高于平均消费额的客户额的客户的总个数
select * from customers;
select count(*) from customers;
mysql> select count(*) from customers;
+----------+
| count(*) |
+----------+
| 10 |
+----------+
select count(*) from customers where customers.id in (select c_id from orders group by c_id having customers.salary > avg(amount));
select * from customers where customers.id in (select c_id from orders group by c_id having customers.salary > avg(amount));