MYSQL 多表查询学习

1.简单查询
内连接查询
1】简单的连接查询
给两个表找中间桥梁: select 字段列表 from 表1,表2 where 表1.s_id=表2.s_id;
eg: select s_name,marks from student_info,marks_info where
student_info.s_id=marks_info.s_id;
eg: select s_name,marks,c_name from
student_info,marks_info,class_info where marks_info.s_id=student_info.s_id and
marks_info.c_id=class_info.c_id;
问题: 如果表名很长,书写繁琐,代码不清晰。
解决: 使用表别名
定义格式 :1】表名 as 别名
2】表名 别名
别名作用域只在本查询语句中
eg : select s_name,c_name,marks from student_info s,marks_info
m,class_info c where s.s_id=m.s_id and m.c_id=c.c_id
查询学生的编号,姓名,科目,成绩
问题: 如果查询的字段在多个表中存在,那么就必须在字段前添加表名或表的别名
select s.s_id,s_name,c_name,marks from student_info s,marks_info
m,class_info c where s.s_id=m.s_id and m.c_id=c.c_id
2】SQL内外连接 (是SQL语言中的多表分类,查询效率比简单查询和子查询在某种情况下要高)
内连接格式:select 字段列表 from 表1 inner join 表2 on 表1.字段=表2.字段
eg :查询学生的姓名和成绩
select s_name,c_name,marks from student_info inner join marks_info on
student_info.s_id=marks_info.s_id inner join class_info on
marks_info.c_id=class_info.c_id;
3】自然查询 : 是简单的查询中去掉重复的记录 在字段中添加distinct
外连接查询 outer join
1】左连接 (left join)select 字段列表 from 表1 left join 表2 on 表1.字段=表2.字段
(查询语句以表1为参照表) 如果表2中有与表1相匹配的记录,那么就显示记录,如果表2中没有与表1相匹配的记录则在相对应的字段上填充null)
问题:如果查询的记录,必须以某个表作为参照表,打印出记录相同的所有的记录
SELECT s_name, marks FROM student_info s LEFT JOIN marks_info m ON
s.s_id = m.s_id
2】右连接 (right join) (查询语句以表2为参照表)
如果表1中有与表2相匹配的记录,那么就显示记录,如果表1中没有与表2相匹配的记录则在相对应的字段上填充null)
SELECT s_name, marks FROM marks_info m RIGHT JOIN student_info s ON
s.s_id = m.s_id
3】全连接 full join (将两个记录集进行合并,并且去掉重复的记录)
mysql 不支持全连接
合并记录集: union (all |distinct)

union all :将两个记录集进行合并,不去掉重复的记录
union (distinct) : ...去掉重复的记录
注意:
----------------------------记录集在合并时,查询的结构(字段类型要完全一样)----------------------------------
eg :
SELECT s_name, marks FROM student_info s LEFT JOIN marks_info m ON s.s_id =
m.s_id
union
SELECT s_name, marks FROM marks_info m RIGHT JOIN student_info s ON s.s_id
= m.s_id
交叉查询
笛卡尔积: cross join
格式: select 字段列表 from 表1 cross join 表2

自查询 :
自己需要的筛选条件来自于自己表的某个字段
feiker (2010-1-15 17:12:27)
MYSQL:
1.问题:检索出本校学生所在的地区有哪些?(记录中有重复)
解决 1.distinct
2.group by
2.问题:检索出id为散列数据(1,3,4)的学生基本信息
1. or -------where id=1 or id=3 or id=4
2. in -------检索散列记录的 where id in (1,3,4); 查询效率比 or 要高
3. 问题: 检索出id 在1和3之间的连续记录
1. between 1 and 3 ;查询效率比 and 高
2. and 和比较运算符 where id>1 and id<3

4. 问题:检索出id 不是4的记录
1. where id <>|!= 4; <>:sql数据库中的不等于 !=:mysql数据库管理系统中的不等于
2. where id not 4;
5. 问题: 检索出id 非散列数据(1,3,4)中的学生记录?
1. not in(1,3,4)
6. 问题: 检索出id 非空记录
记录为空: 中间没有记录,但记录存在 =''

103f
自己打的null: 打入的字符串为null 查询用='null'
系统null : 就是记录没有定义 is null
7. 问题: 根据字段中的某些查询数据:
检索出学生名中含有d字符的所有记录
‘_’ :代表任意一个字符
'%': 代表任意的多个字符
_d_
like 尽量不要使用like %d%
注意: 在Mysql 查询语句中尽量不要使用like 模糊查询,使用时尽量不要使用%开头
聚合函数尽量要和group by 一起使用 (先分组后计算)
只计算各个组内的数据
格式: 函数名(distinct|all 字段名|*)
有distinct 先筛选在->分组->计算
8. 字段别名 : 字段名 as 新名字

*9. SQL语言的常量
问题: 如何检索出下面格式的数据
编号 1 tom
编号 2 jjj
编号 3 hhh

解决方案
定义格式: select '编号',s_id,s_namefeiker (2010-1-15 17:13:06)
1.多表查询
超过一个表的综合查询
注意找到表与表之间的纽带
分类
1.内连接
等值连接---查询结果带有重复记录
select 字段列表 from 表列表 where 表1.字段1=表2.字段1 and
表1.字段2=表2.字段2 and......
如果查询的字段在多个表中存在 要使用"表明.字段名"的方式来表明字段是哪个表中的
e.g:select
student_info.s_id,s_name,age,area,c_name,mark from student_info,marks,class
where student_info.s_id=marks.s_id and marks.c_id=class.c_id
如果重复字段较多 可以给使用的表起别名
表名 as 别名|表名 别名
e.g:select s.s_id,s_name,age,area,c_name,mark
from student_info as s,marks as m,class as c where s.s_id=m.s_id and
ms.c_id=c.c_id
先分组后计算
e.g:select c_name,avg(mark) as "平均成绩" from
class,marks where class.c_id=marks.c_id group by c_name

不等值连接
自然连接---查询结果没有重复记录(distinct|group by)

2.外连接
左连接
右连接
全连接

3.交叉连接
cross---select 字段列表 from 表1 cross join 表2
e.g:select s_name,mark from student_info cross join
marks

4.自连接
inner join
sql语句中
内连接
select 字段列表 from 表1 inner join 表2 on
表1.字段1=表2.字段2
e.g:select s_name,mark from student_info
inner join marks on student_info.s_id=marks.s_id

外连接
左连接
select 字段列表 from 表1 left outer join 表2 on
表1.字段1=表2.字段1
e.g:select s_name,mark from student_info left
outer join marks on student_info.s_id=marks.s_id
注意 以左边的表为标准 用右边的表进行匹配 如果右边表中有匹配的记录 那么显示
没有就填充null

右连接
select 字段列表 from 表1 right outer join 表2 on
表1.字段1=表2.字段1
e.g:select s_name,mark from student_info right
outer join marks on student_info.s_id=marks.s_id
注意 以右边的表为标准 用左边的表进行匹配 如果左边表中有匹配的记录 那么显示
没有就填充null

全连接---在mysql中不支持全连接 或使用union all
union all 将两个记录集合并 不去除重复记录 默认情况下没有all
相当于加了distinct去掉重复记录 相当于全连接

2.嵌套查询(子查询)
内查询记录比较庞大 而最后需要的查询结果却寥寥无几时
select 字段列表 from 表1 where 字段 in、>、<、any、all、some、exists(筛选后的字段)
e.g:select s_name f
103f
rom student_info where s_id in(select s_id
from marks where mark>60)
any 任何一个符合条件
all 子查询所有结果都成立 此条件才成立
exists 子查询中有结果返回 那么主查询就执行 如果没有结果返回
运算符
> 、< 、>= 、<= 、!= 、<>、in、all、any、exists
not (in|all|any|exists)

3.视图
源于表而又高于表的虚拟表
视图可以像正常表进行查询 但是不能进行添加删除 可以修改
格式---create view 视图名 as 查询语句
范围 频繁使用到多个表中的数据时 将使用到得数据生成视图
删除视图---drop view 视图名;完全一样
php中使用视图---与普通表查询

4.索引:在记录上建立的虚拟目录
索引文件目录->索引文件件->记录

1.避免查询数据时进行全表扫描,插入和删除更快
2.在使用max、min等聚合函数时更加有效
3.多表查询时更加有效

缺点 1.浪费磁盘空间 2.索引过多 使索引文件目录过大 降低查询速度

索引分类
按纪录性质分
普通索引---可以在任何的字段上建立索引
唯一索引---不能在重复的记录上建立索引
主键---索引名唯一 记录唯一
按索引占有的字段分
单列索引
多列索引
按索引的内容来分
短索引(最左前缀)---将字段上的部分数据作为索引内容

创建普通索引方法-----标示符:key->mul (desc 表名查看)----不唯一 可以有重复记录
Non_unique 是否索引唯一
已存在表
create index 索引名 on 表名(字段名);
e.g.create index id_index on student_info(s_id)
查看方法
show index fron 表名;e.g.SHOW INDEX FROM
student_info
已存在表 修改表的命令
alter table 表名 add index 索引名(索引字段);
e.g.alter table student_info add index name_index (s_name);
不存在表 创建索引
create table person (pid int(4),pname
char(30),index 索引名(字段名));

唯一索引 索引唯一记录可重复-----标示符:key->unl
创建方法
create unique index 索引名 on 表名(字段名);
e.g.create unique index id_index on student_info(s_id)
已存在表 修改表的命令
alter table 表名 add unique 索引名(索引字段);
e.g.alter table student_info add unique name_index (s_name);
不存在表 创建索引
create table person (pid int(4),pname
char(30),unique 索引名(字段名));

主键 索引唯一 建索引的字段记录唯一-----标示符->pri
不存在表 创建单列主键
create table person (pid int(4),pname
char(30),primary key 索引名(字段名));
不存在表 创建多列主键
create table person (pid int(4),pname
char(30),primary key 索引名(字段名 字段名));
表存在 增加主键
alter table表名 add primary key(字段列表)
如果一个字段不能唯一的表示一条记录的话 那么我们可以使用多个字段唯一的表示一条记录 这个就叫做多列主键

三种索引区别
普通索引:可以在任何字段上建立
唯一索引:一个表中可以建立多个 记录不能有重复 记录可以为空
主键:一个表只能有一个 记录不能重复 也不能为null

单列索引 单列普通索引|唯一索引|单列主键
多列索引 多列普通索引|唯一索引|多列主键
已存在表
create index 索引名 on 表名(字段列表);
e.g.create index id_index on student_info(s_id,s_name)
查看方法
103f

show index fron 表名;e.g.SHOW INDEX FROM
student_info
已存在表 修改表的命令
alter table 表名 add index 索引名(索引字段);
e.g.alter table student_info add index name_index (s_name);
不存在表 创建索引
create table person (pid int(4),pname
char(30),index 索引名(字段列表));
优点
建立一个多列索引相当于建立多个单列索引
节省磁盘空间

短索引:必须建立在字符型或者文本型的字段上
普通短索引 唯一短索引
Sub_part :标明是短索引 里面是截取的字符数
表已存在
create index 索引名 on 表名(字段列表)
e.g:create index index1 on news(title(10))
什么地方建立索引
一般只在设计数据库已经设计在内
where语句后频繁出现的字段 在此字段上建立
删除索引
1.drop index 索引名 on 表名
2.alter table 表名 drop index 索引名
选择索引列:
1)搜索的索引列,不一定是所要选择的列。换句话说,最适合索引的列是出现在WHERE
子句中的列,或连接子句中指定的列,而不是出现在SELECT 关键字后的选择列表中的列:
2)对于惟一值的列,索引的效果最好(性别不行)
3)多列索引相当于,多个索引
6.程序逻辑
1.存储过程
存储子程序,mysql的自定义函数 有自己的控制结构和检测语句
变量的定义 :@;
set @var='100';
输出语句:
select 变量名
同时定义多个变量
set 变量[=值],变量2[=值]
储存过程的定义格式
create procedure 存储过程名(in|out|inout 参数名 类型)
储存主题
步骤
定义界定符
delimiter //
1.定义存储过程
定义变量 (out,inout)
2.调用存储过程(call 存储过程名)
查询变量结果
e.g:select * from student_info;
create procedure stu_pro()
select * from student_info;
call stu_pro();
语句块 begin 过程体 end
存储过程中的三种参数
in ---相当于php中的形参 往存储过程中传值
out---相当于php中的return 从存储过程带回值
存储过程中能有多个out型参数 但是php中只能有一个return
inout---传入传出参数

e.g:检索出id=3|4|5的信息
create procedure stu_id_pro(in sid
int(4))
begin
select * from student_info where
s_id=sid;
end
//
call stu_id_pro(3);
//

传出参数
create procedure stu(out sid int (4))
begin
set sid=100;
end
//
set @a=0;
//
call stu(@a);
//
select @a;
//


103f
变量赋值
set 变量名=值
select 字段名 into 变量名 from 表名 where sid=值
赋值只能一个
返回id=3的年龄返回
create procedure age(in sid int(4),out age1
int(4))
begin
select age into age1 from
student_info where s_id=sid;
end//
call age(3,@a)//
select @a//
inout参数 e.g使用存储过程使变量值+1返回
create procedure sum1(inout a int (4))
begin
set a=a+1;
end//
set @p=100//
call sum1(@p)//

select @p//
程序控制结构
分支语句
单分支语句 if
多分支语句 case
循环
while
repeat
loop
1.if语句
if 条件 then
操作
elseif 条件
else
end if
create procedure if_pro(in tag int(4))
begin
if tag=1 then
select * from
student_info;
else
elect * from
class;
end if ;
end//

2.case
case 变量名
when 值 then 操作
else
操作;
end case;
create procedure if_pro1(in tag int(4))
begin
case tag
when tag=1 then
select * from student_info;
when tag=2 then
select * from class;
when tag=3 then
select * from people;
else
select * from person;
end case;
end//

[2]
case
when 条件1 then 操作1
when 条件2 then 操作2
...
else
操作
end case;
create procedure if_pro2(in tag int(4))
begin
case tag
when tag>6 then
select * from student_info;
when tag>3
103f
then
select * from class;
else
select * from person;
end case;
end//

while循环-----条件成立时执行循环
while 条件 do
操作
end while
e.g create procedure sums1()
begin
declare tag int(4) default 0;
declare num int(4) default 0;
while num<=10 do
set tag=num+tag;
set num=num+1;
end while;
select tag;
end//

repeat-----条件成立退出循环
repeat
操作
until
end repeat
e.g create procedure sums2()
begin
declare tag int(4) default 0;
declare num int(4) default 0;
repeat
set num=num+1;
set tag=num+tag;
until num>=10
end repeat;
select tag;
end//


loop循环
leave:跳出循环
标签名:loop
操作
if 条件成立 then
leave 标签名;
else
iterate 标签名;
end loop 标签名;
e.g:
create procedure sums3()
begin
declare tag int(4) default 0;
declare num int(4) default 0;
loop1:loop
set num=num+1;
set tag=num+tag;
if num>=10 then
leave loop1;
else
iterate loop1;
end if;
end loop loop1;
select tag;
end//

存储过程---游标 用来存储记录集(数据结构)
步骤
1.定义游标
declare cursor 游标名 for select 语句
2.打开游标
open 游标名;
3.取得游标中的每条记录
fetch 游标名 into 变量列表;
fetch 语句触发handler 根据handler有两条路可走 1.继续往下执行 2.捕获错误 设置错误标示
循环依靠handler执行的结果判断是否循环取值
4.关闭游标
close 游标名;

mysql错误句柄
declare 执行什么操作(continue|exit) handler for sqlstate 错误类型 set 操作
e.g:declare continue handle for sqlstate "0200" set tag=1;
错误类型
01---sql错误
02---数据未发现错误

/**********************************************e.g.********************************************************
create procedure money_pro3()
begin
declare a int(4) default 0;
declare b int(4) default 0;
declare tag int(4) default 0;
declare cur1 cursor for select sid,marks from stu;
declare continue handler for sqlstate "02000" set tag=1;
open cur1;
repeat
fetch cur1 into a,b;
if b<60 then
update stu set money=500 where sid=a;
elseif b<70 then
update stu set money=1000 where sid=a;
elseif b<80 then
update stu set money=2000 where sid=a;
elseif b<90 then
update stu set money=3000 where sid=a;
else
update stu set money=4000 where sid=a;
end if;

until tag

103f
end repeat;
close cur1;
end


create procedure cha3()
begin
declare a int(4) default 0;
declare b int(4) default 0;
declare c int(4) default 0;
declare tag int(4) default 0;
declare cur1 cursor for select a.id,a.num,b.num from a,b where
a.id=b.id;
declare continue handler for sqlstate "02000" set tag=1;
open cur1;
repeat
fetch cur1 into a,b,c;
if b<c then
update a set a.num=c where id=a;
update b set b.num=b where id=a;
end if;
until tag
end repeat;
close cur1;
end
************************************************************************************/

2.触发器
存储过程是用户手动调用的mysql程序逻辑
触发器是用户执行某种操作之后 mysq自动执行的程序逻辑
创建触发器的语句
create trigger 触发器名
before|after
insert|update|delete //触发操作
on 表名称
for each row
begin
触发器sql语句
end
触发时间
before e.g:before delete on stu;-----在删除stu表的记录前触发
after e.g:after delete on stu;-----在删除stu表的记录后触发
关键字
new old
在插入操作时只有new
更新时new为即将更新的数据 old为原数据
在删除操作时只有old

create trigger sum
before
insert
on a
for each row
begin
set new.num=new.num+1;
end


create trigger change3
after insert on student
for each row
begin
declare a int(4) default 0;
declare b char(30);
declare tag int(4) default 0;
declare t int(4) default 0;
declare cur1 cursor for select name from school;
declare continue handler for sqlstate "02000" set tag=1;
open cur1;
repeat
fetch cur1 into b;
set a=new.school;
if b=a then
set t=1;
end if;
until tag
end repeat;
if t=0 then
select "hello";
insert into school(name) values('a');
end if;
close cur1;
end

存储过程在php中的使用-----在mysq中用于存储过程的命令 在php中使用mysql_query()来执行
php中mysql函数不支持结果集的返回 使用pdo mysql里数据库抽象层 或mysql扩展类

create procedure pro2(in a int(4),out b int(4))
begin
set b=a;
end

7.数据库优化(sql语句的优化和数据库设计的优化)
1.编码问题---设计数据库的编码和浏览器上的编码统一
客户端编码和服务器编码 浏览器会自动转换
2.设计表时,不能出现表中有表的情况
3.在同一表中字段尽量不要很多
4.在同一数据库中不能出现很多表--------1000表
5.字段中设计字段类型时尽可能使用较小的类型 char要比varchar小得多 int比double、float小
6.使用存储过程替代php频繁的访问数据库的简单逻辑
7.索引要有用时才能建立 不能建立很多的索引浪费空间,降低索引效率
8.设计数据库时尽量让设计的数据库符合第三范式
9.在设计字段时,字段能不为null的就不为null-------not null
具体操作优化
1.查询时不要查询不必要的字段
2.尽量不使用模糊查询,如果必须使用 尽量不要在规则内有百分号
3.在合理的字段上建立索引 可以加快连接查询的速度
4.使用join链接代替普通的多表连接(=)
如果连接的字段上有索引,那么使用join连接查询代替子查询如果没有索引,子查询中的记录很大而有效记录很小,那么推荐使用子查询,但是子查询的深度不能过深
5.如果表中多个字段经常同时出现在where后,那么建立多列索引
6f7

6.在记录集合并时---union,尽量的不要删除重复的记录而使用union all
7.使用聚合函数时,尽量不要使用where语句 count(sid)
8.group by 分组和order by排序时,如果后面跟的字段一样,那么顺序要一样
9.建立索引时,尽量的建立短索引
10.建立索引时,尽量的建立唯一索引
11.在插入数据时,尽量的写出被插入的字段列表,而不是*
12.频繁使用到多表中的数据时,建立视图
13.where语句后的多个条件是,尽量的将能多记录过多筛选的条件放到前面
14.where语句多个条件时,去掉不必要的()和不必要的条件
15.插入数据时:插入数据

1.insert values;
2.insert values,values,values;
3.load
插入速度 高------>低
批量插入------>多条记录插入------>单条注意插入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值