子查询
代码:select * from tableName where id in(select id from tableName1 where age=18)
子查询的结果可以用以下不同的方法进行测试:
- 标量子查询(返回单个结果)可以用诸如”
=
“或”<
“之类的相对比较符,进行求值。 - 可以用
in
和not in
操作符测定给定的值是否在子查询的查询结果集里面。 - 可以用
all
、any
和some
操作符把某给定的值与子查询的结果集进行比较。 - 可以用
exists
和not exists
操作符来测试子查询的结果集是否为空。
在子查询中可以引用主查询里的值,也可以与之不相关。除了SELECT
,子查询还可以用于其它语句。如果把子查询用在一条会改变表内容(INSERT
、UPDATE
、DELETE
...)的语句里,目前必须遵守这么一条限制:
子查询不允许引用正在被修改的表。简单的来说,就是不能同一张表。那么查询语句能不能主查询与子查询表一样呢?答案是肯定的,查询操作不会改变表内容。
代码:select columns from tableName where (column1,column2)=(select column1,column2 from tableName where id=1 limit 1)
上面的例子,子查询返回的是一个数据行,对于数据行可以用一个数据行构造器把一组值与子查询查出来的结果进行比较。后面的limit 1
限定子查询只能返回一个数据行(在不确保子查询的where
条件只返回一条记录的情况下,建议用limit 1
)。如果查询结果多于一条记录,mysql会报错:Subquery returns more than 1 row
。在上述的例子中如果需要在子查询中返回多条记录,主查询只需在返回的结果集中匹配一条记录,则把=
替换成in
即可。同理,not in
是指在主查询中查询不包含在子查询中的结果集。
(column1,column2) 用来生成一条临时记录与子查询返回的一条记录进行对比,也可以写成row(column1,column2) 结果都是一样的。
ALL、ANY和SOME子查询
代码:select columns from tableName where id <= all(select id from tableName)
all
和any
操作符的常见用法是结合一个相对比较操作符('=','<','>'...),对子查询的查询结果集进行过滤。上面的列子中如果id小于等于子查询中返回的每一个值,<= all
将返回true;只要id小于或等于子查询返回的任意一个值 <= any
将返回true。some
是any
的同义词
概念都是苦涩的,除非真的理解了,才觉得它抽象的那么有内涵。才懂这是精华啊,下面来几个不内涵,不精华的。
首先来看看 all
代码:select columns from tableName where id <= all(select id from tableName)
首先假设子查询(select id from tableName)返回的结果集为 1,2,3,4,5
翻译一下:
select colums from tableName where id <= 1 and id<=2 and id<=3 and id<=4 and id<=5;
然后来看看any或者some
翻译一下:
select colums from tableName where id <= 1 or id<=2 or id<=3 or id<=4 or id<=5;
翻译完了,我就不说话了,然后都懂了么?懂了么~再仔细想想,是不是可以用= any
代替in
,用<> all
代替not in
。
再解释下 in 和 not in
in:
就是相当于要查找的条件在一个集合里有交集。如 id in(1,2,3) 如id 是1或2或3中的任意一个则返回true 反之返回false
not in:
就是要查找的条件不在这个集合里面,取差集。还是上面的例子 如果id为5 不在集合(1,2,3)里返回true,集合里有一个值与id匹配都将返回false
EXISTS 和 NOT EXISTS 子查询
代码:select exists (select * from tableName)
exists
和 not exists
操作符只测试某个子查询是否返回了数据行。如果有数据返回exists
将是true,not exists
将是false。
from子句中的子查询
代码:select * from (select 1,2) AS tab1 inner join (select 3,4) as t2
子查询可以在from子句里面生成一些值。这种情况,子查询在行为上就像是一个数据表。在使用这种子查询的时候必须提供一个数据表别名作为子查询结果的名字。
关于子查询
在相当一部分子查询的查询命令中,都可以改写成联结查询。有的时候,联结查询比子查询的效率更高。如果使用子查询需要很长的时间执行完毕,可以试着改写成一个联结查询。
用union语句进行多数据表检索
代码:select column1,column2 from tableName where id<10 union select column1,column2 from tableName
使用union
进行组合查询注意点:
-
union
必须有两条或两条以上的select
语句组成 -
union
的每个查询必须包含相同的列数,表达式,聚集函数...次序没有关系,mysql会进行自动类型转换。 -
union
会默认去除重复的行。union
是union distinct
的缩写。如果不想让union
去除重复的行可使用union all
- 在对组合查询结果集排序时,只能出现一条
order by
语句 并跟随在union
的最后一条子查询。它将排序整个结果集,而不是最后一条检索的数据。order by
用于排序的列必须引用在第一个select语句中的列。 - 如果把
union
和union all
混杂在一起使用,每个union
操作符将优先于它左边的任何union all
操作。
联结查询####
内联结
下面模拟两张关系表:
t1表
i1 | c1 |
---|---|
1 | a |
2 | b |
3 | c |
t2表
i2 | c2 |
---|---|
2 | c |
3 | b |
4 | a |
代码:select * from t1 inner join t2
上面的代码总共会产生9条记录。t1表里的每行记录与t2表里的每行记录得到全部可能的组合的操作叫做生成笛卡尔积。通常需要限制结果集,得到我们想要的数据需要加一个where
子句。
代码:
select t1.*,t2.* from t1 inner join t2 where t1.i1=t2.i2
select t1.*,t2.* from t1 cross join t2 where t1.i1=t2.i2
select t1.*,t2.* from t1,t2 where t1.i1=t2.i2
上面的代码写法是等价的。可把上面前两条语句改把where
写成on
去匹配条件。用','分割联结的表,不能使用on
代码:
select tab1.* ,tab2.* from tab1 inner join tab2 usign(id)
使用usign()
,在概念上类似于on
。但要求被联结的数据列必须是同名的。
左联结和右联结(外联结)
内联结只显示在两个数据表里能匹配的数据行。外联结除此之外,还可以把其中一个数据表在另一个数据表中没有匹配的记录显示出来。
left join
:
来自左表的数据行,与来自右表的数据行匹配。两个表的数据行将被选取为一个输出数据行,如果来自左表的数据行,在右表找不到匹配
,它也会选取一个输出数据行,此时它联结的是来自右表的一个“假”数据行,这个“假”数据行的所有列都 包含null值。
例子:select * from t1 left join t2 ON t1.i1=t2.i2;
right join
:
来自右表的数据行,与来自左表的数据行匹配。两个表的数据行将被选取为一个输出数据行,如果来自右
表的数据行,在左表找不到匹配,它也会选取一个输出数据行,此时它联结的是来自左表的一个“假”数据行,这个“假”数据行的所有列都包含null值。
例子:select * from t1 right join t2 ON t1.i1=t2.i2;
有没发现,上面两段哄鬼的话,仅仅是左右两个字不同而已。不管是左联结还是右联结都可互换使用,只需要把表名位置左右互换一下,用left join
(或right join
) 都可以达到左右联结的效果。
多个数据表的删除和更新操作
有时候我们可以根据某个数据表里的数据行在另一个表里是否有匹配来删除它们,也可以用一个数据表里的内容去更新另外一个数据表。
代码:delete tab1,tab2 from tab1 inner join tab2 on tab1.id=tab2.id
上面的例子可以一次删除tab1和tab2两个表里的数据行。删除多个表里的数据,表名跟在delete
后面“,”隔开。mysql还支持另一种多个数据表的delete
语法,使用using
看下面代码:
代码:delete from tab1 using inner join tab2 on tab1.id = tab2.id
多个表的更新语法,与删除差不多
代码:
update tab1,tab2 set tab1.name='jiejie' where tab1.id=tab2.id
update tab1,tab2,set tab2.name=tab1.name where tab1.id=tab2.id
昂~罗嗦一句,不建议用外键去维护数据表的完整性,潜意识被人忘记的东西。都写在应用层吧。