SQL技术:sql语句子查询大全

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} -->

left join( 左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
right join(
右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
inner join(
等值连接) 只返回两个表中联结字段相等的行

举例如下:
--------------------------------------------
A 记录如下:
aID
     aNum
1
     a20050111
2
     a20050112
3
     a20050113
4
     a20050114
5
     a20050115

B 记录如下:
bID
     bName
1
     2006032401
2
     2006032402
3
     2006032403
4
     2006032404
8
     2006032408

--------------------------------------------
1.left join
sql
语句如下:
select * from A
left join B
on A.aID = B.bID

结果如下:
aID
     aNum      bID      bName
1
     a20050111     1      2006032401
2
     a20050112     2      2006032402
3
     a20050113     3      2006032403
4
     a20050114     4      2006032404
5
     a20050115     NULL      NULL

(所影响的行数为 5 行)
结果说明:
left join
是以A 表的记录为基础的,A 可以看成左表,B 可以看成右表,left join 是以左表为准的.
换句话说, 左表(A) 的记录将会全部表示出来, 而右表(B) 只会显示符合搜索条件的记录( 例子中为: A.aID = B.bID).
B
表记录不足的地方均为NULL.
--------------------------------------------
2.right join
sql
语句如下:
select * from A
right join B
on A.aID = B.bID

结果如下:
aID
     aNum      bID      bName
1
     a20050111     1      2006032401
2
     a20050112     2      2006032402
3
     a20050113     3      2006032403
4
     a20050114     4      2006032404
NULL
     NULL      8      2006032408

(所影响的行数为 5 行)
结果说明:
仔细观察一下, 就会发现,left join 的结果刚好相反, 这次是以右表(B) 为基础的,A 表不足的地方用NULL 填充.
--------------------------------------------
3.inner join
sql
语句如下:
select * from A
innerjoin B
on A.aID = B.bID

结果如下:
aID
     aNum      bID      bName
1
     a20050111     1      2006032401
2
     a20050112     2      2006032402
3
     a20050113     3      2006032403
4
     a20050114     4      2006032404

结果说明:
很明显, 这里只显示出了 A.aID = B.bID 的记录. 这说明inner join 并不以谁为基础, 它只显示符合条件的记录.
--------------------------------------------
:
LEFT JOIN
操作用于在任何的 FROM 子句中,组合来源表的记录。使用 LEFT JOIN 运算来创建一个左边外部联接。左边外部联接将包含了从第一个(左边)开始的两个表中的全部记录,即使在第二个(右边)表中并没有相符值的记录。

语法:FROM table1 LEFT JOIN table2 ON table1.field1 compopr table2.field2

说明:table1, table2 参数用于指定要将记录组合的表的名称。
field1, field2
参数指定被联接的字段的名称。且这些字段必须有相同的数据类型及包含相同类型的数据,但它们不需要有相同的名称。
compopr
参数指定关系比较运算符:"=" "<" ">" "<=" ">=" "<>"
如果在INNER JOIN 操作中要联接包含Memo 数据类型或 OLE Object 数据类型数据的字段,将会发生错误.

 

一、有 = <> > < >= <= 的子查询
格式:
SELECT col1 , col2 , col3
FROM tb
WHERE col = [ANY | SOME | ALL](
SELECT coln FROM tb WHERE ...
)

举例:
SELECT `ID`, `classname`
FROM `ydfzx_software_class`
WHERE `fatherid` = ANY(
SELECT `id`
FROM `ydfzx_software_class`
WHERE `fatherid`=13
)

在这个查询中,子查询返回一个离散值( 一列一行) ,如果有ANYALL 的修饰,可以返回一个离散值列表(一列多行) , 其实 col = ANY 就相当于col IN


二、IN 子查询
格式:
SELECT col1 , col2 , col3
FROM tb
WHERE col [NOT] IN(
SELECT coln FROM tb WHERE ...
)

在有IN 谓词的这个子查询中,返回一个离散值列表(一列多行)



三、SELECT ROW 字查询,注意返回值是01
格式:
SELECT ROW(value1,value2,value3 ...) = [ANY | SOME] SELECT col1,col2,col3

如果第2 条查询必须返回一组离散值(多列单行),如果有ANYSOME 谓词的修饰,返回一组离散值列表
举例:
SELECT ROW(1,'
操作系统'1) = ANY (SELECT `ID`,`caption`,`status` FROM `ydfzx_software_class`)
`ydfzx_software_class` 里查找有没有`ID`=1`caption`=' 操作系统',`status`=1 的记录,有就返回1 ,没有就返回NULL 0


四、EXISTS 子查询
格式:
SELECT col1,col2 FROM a WHERE EXISTS(SELECT ...)
解释:
主查询先查询出数据, 再逐条通过EXISTS 子查询验证, 只有子查询返回的记录数不为0, 主查询中的记录有效. 这个查询开销比较大

users

┏━━━┯━━━┯━━━━┓
┃ uid │ name │address ┃
┃ 1 │
张荣 中光
┃ 2 │
晨曦 │fuyang ┃
┃ 3 │
川湘 中光
┃ 4 │
张荣 浙江
┗━━━┷━━━┷━━━━┛
xl

┏━━━┯━━━┯━━━━┓
┃ uid │ xl │year ┃
┃ 1 │
大专 │2007 ┃
┃ 1 │
大本 │2008 ┃
┃ 1 │
硕士 │2009 ┃
┃ 2 │
小学 │2012 ┃
┃ 2 │
初中 │2018 ┃
┃ 2 │
高中 │2021 ┃
┃ 2 │
大本 │2025 ┃
┃ 4 │
大本 │2025 ┃
┃ 5 │
大本 │2025 ┃
┃ 3 │
大专 │1995 ┃
┃ 3 │
大本 │2001 ┃
┗━━━┷━━━┷━━━━┛


举例:找出users 表中那些在xl 表中有xl= 小学的记录,他们的共同键为id
SELECT *
FROM `users`
WHERE EXISTS (
SELECT *
FROM `xl`
WHERE `xl`.`uid` = `users`.`uid` AND xl = '
小学'
)
等效于:
SELECT `users`. *
FROM `users` , `xl`
WHERE `xl`.`xl` = '
小学' AND `users`.`uid` = `xl`.`uid`

得到的结果为:

┏━━━┯━━━┯━━━━┓
┃ uid │name │address ┃
┃ 2 │
晨曦 │fuyang ┃
┗━━━┷━━━┷━━━━┛



五、衍生数据表子查询
格式: SELECT ... FROM (SELECT ...) AS name WHERE
首先执行子查询生成临时表,外层查询再到此临时表中获取数据。
举例:
SELECT `users`.`uid` , `users`.`name` , count( `xl`.`uid` ) AS lcount
FROM `users` , `xl`
WHERE `users`.`uid` = `xl`.`uid`
GROUP BY `users`.`uid`
ORDER BY `lcount` DESC

等效于:
SELECT *
FROM(
SELECT `users`.`uid` , `users`.`name` , count( `xl`.`uid` ) AS lcount
FROM `users` , `xl`
WHERE `users`.`uid` = `xl`.`uid`
GROUP BY `users`.`uid`
) AS `temp`
ORDER BY `lcount` DESC

有一存储树形目录的表tb, 共有3 个字段,IDclassname,fatherid, 每个节点一条记录.ID 字段为非重复字段,classname 为此节点的名称, 每个子节点的fatherid 等于其父节点的ID ,如果fatherid0 ,表示它为顶层节点,如何能一次就查询

出各顶层节点有没有子节点呢,经过调试,以下语句执行成功。

SELECT `ID` , `classname` , `fatherid` ,

IF(
(SELECT COUNT(`ID` )
FROM `tb`
WHERE `fatherid` = `main`.`ID`
) >0, 1, 0) AS `haveson`

FROM `tb` AS `main`
WHERE `fatherid` =0

2 、一次性查询出某节点的兄弟节点
SELECT *
FROM `tb`
WHERE `fatherid`=(SELECT `fatherid` FROM `tb` WHERE `ID`=6)

3
、一次性查询出某节点的父辈节点
SELECT *
FROM `tb`
WHERE `fatherid`=(
SELECT `fatherid`
FROM `tb`
WHERE `ID`=(SELECT `fatherid` FROM `tb` WHERE `ID`=13)
)

exists in

in 适合内外表都很大的情况,exists 适合外表结果集很小的情况。

http://blog.itpub.net/category/385/14461

exists in 使用一例
===========================================================
今天市场报告有个sql 及慢,运行需要20 多分钟,如下:
update p_container_decl cd
set cd.ANNUL_FLAG='0001',ANNUL_DATE = sysdate
where exists(
select 1
from (
select tc.decl_no,tc.goods_no
from p_transfer_cont tc,P_AFFIRM_DO ad
where tc.GOODS_DECL_NO = ad.DECL_NO
and ad.DECL_NO = 'sssssssssssssssss'
) a
where a.decl_no = cd.decl_no
and a.goods_no = cd.goods_no
)
上面涉及的3 个表的记录数都不小,均在百万左右。根据这种情况,我想到了前不久看的tom 的一篇文章,说的是existsin 的区别,
in
是把外表和那表作hash join ,而exists 是对外表作loop ,每次loop 再对那表进行查询。
这样的话,in 适合内外表都很大的情况,exists 适合外表结果集很小的情况。

而我目前的情况适合用in 来作查询,于是我改写了sql ,如下:
update p_container_decl cd
set cd.ANNUL_FLAG='0001',ANNUL_DATE = sysdate
where (decl_no,goods_no) in
(
select tc.decl_no,tc.goods_no
from p_transfer_cont tc,P_AFFIRM_DO ad
where tc.GOODS_DECL_NO = ad.DECL_NO
and ad.DECL_NO = ‘ssssssssssss’
)

让市场人员测试,结果运行时间在1 分钟内。问题解决了,看来existsin 确实是要根据表的数据量来决定使用。

not in <>not exists

请注意not in 逻辑上不完全等同于not exists ,如果你误用了not in ,小心你的程序存在致命的BUG

 

请看下面的例子:
create table t1 (c1 number,c2 number);
create table t2 (c1 number,c2 number);

insert into t1 values (1,2);
insert into t1 values (1,3);
insert into t2 values (1,2);
insert into t2 values (1,null);

select * from t1 where c2 not in (select c2 from t2);
no rows found
select * from t1 where not exists (select 1 from t2 where t1.c2=t2.c2);
c1 c2
1 3

正如所看到的,not in 出现了不期望的结果集,存在逻辑错误。如果看一下上述两个select 语句的执行计划,也会不同。后者使用了hash_aj
因此,请尽量不要使用not in( 它会调用子查询) ,而尽量使用not exists( 它会调用关联子查询) 。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录,正如上面例子所示。
除非子查询字段有非空限制,这时可以使用not in , 并且也可以通过提示让它使用hasg_ajmerge_aj 连接。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值