【 文章摘要 】
“SYBASE数据库不支持子查询,所以……”,在数据库开发中我们常常听到这样的话语,SYBASE数据库真是如此吗?让我们一起走进SYBASE数据库,看看它支持与不支持的子查询语句分别有哪些。希望对大家有所帮助。
【 关键词 】
Sybase 12.5.0.3、子查询
【 参考资料 】
Microsoft SQL Server 2000联机丛书
【 测试环境 】
Adaptive Server Enterprise/12.5.0.3/EBF 11449 ESD#4/P/NT (IX86)/OS 4.0/rel12503/1939/32-bit/OPT/Sat Sep 20 22:28:57 2003
一、SYBASE支持的子查询
1、UPDATE、DELETE 和 INSERT 语句中的子查询
子查询可以嵌套在 UPDATE、DELETE 和 INSERT 语句以及 SELECT 语句中。
下面的查询使由 New Moon Books 出版的所有书籍的价格加倍。该查询更新 titles 表;其子查询引用 publishers 表。
UPDATE titles
SET price = price * 2
WHERE pub_id IN
(SELECT pub_id
FROM publishers
WHERE pub_name = 'New Moon Books')
通过下面嵌套的查询,可以删除出版商业书籍的所有出版商的记录:
DELETE publishers
WHERE pub_id IN
(SELECT pub_id
FROM titles
WHERE type = 'business')
2、使用 EXISTS 、NOT EXISTS和IN、NOT IN的子查询
使用 EXISTS 关键字引入一个子查询时,就相当于进行一次存在测试。外部查询的 WHERE 子句测试子查询返回的行是否存在。子查询实际上不产生任何数据;它只返回 TRUE 或 FALSE 值。
使用 EXISTS 引入的子查询语法如下:
WHERE[NOT]EXISTS(subquery)
下面的查询以EXISTS为例查找所有出版商业书籍的出版商的名称:
SELECT pub_name
FROM publishers
WHERE EXISTS
(SELECT *
FROM titles
WHERE pub_id = publishers.pub_id
AND type = 'business')
下面的查询查找所有没有出版商业书籍的出版商的名称:
SELECT pub_name
FROM publishers
WHERE pub_id NOT IN
(SELECT pub_id
FROM titles
WHERE pub_id = publishers.pub_id
AND type = 'business')
3、使用比较运算符的子查询
子查询可由一个比较运算符(=、< >、>、>=、<、!>、!<或<=)引入。
要使用比较运算符引入的子查询,必须对数据和问题的本质非常熟悉,以了解该子查询返回一个值还是值列表。
例如,如下查询将显示价格不是最低的书目。
SELECT DISTINCT title
FROM titles
WHERE price >
(SELECT MIN(price)
FROM titles)
4、使用别名的相关子查询
相关子查询可以用于从外部查询引用的表中选择数据之类的操作。在这种情况下,必须使用表的别名(也称为相关名)明确指定要使用哪个表引用。例如,可以使用相关子查询查找已由多个出版商出版的书的类型。需要用别名来区分在其中出现 titles 表的两个不同角色。
SELECT DISTINCT t1.type
FROM titles t1
WHERE t1.type IN
(SELECT t2.type
FROM titles t2
WHERE t1.pub_id <> t2.pub_id)
5、HAVING 子句中的相关子查询
相关子查询还可以用于外部查询的 HAVING 子句。如下的查询可查找最高预付款超过给定类型中平均预付款两倍的书籍类型。
SELECT t1.type
FROM titles t1
GROUP BY t1.type
HAVING MAX(t1.advance) >=ALL
(SELECT 2 * AVG(t2.advance)
FROM titles t2
WHERE t1.type = t2.type)
6、测试脚本:
-- 测试创建语句和测试数据:
if exists (select * from sysobjects where name = 'titles')
drop table titles
go
create table titles(
title_id int not null,
title varchar(80) not null,
type char(12) default 'UNDECIDED' not null ,
pub_id char(4) null,
price money null,
advance money null,
royalty int null,
ytd_sales int null,
notes varchar(200) null,
pubdate datetime default GETDATE() not null
)
go
alter table titles add constraint pk_titles primary key(title_id)
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(1,'数据库系统原理','DATABASE','0001',32,20,1,100,'',getdate())
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(2,'Informix使用全书','DATABASE','0001',160,140,1,200,'',getdate())
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(3,'Eclipse','Computer','0002',20,10,1,100,'',getdate())
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(4,'Bank Management','business','0002',23,10,1,100,'',getdate())
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(5,'Company Management','business','0001',132,100,1,100,'',getdate())
go
insert into titles(title_id,title,type,pub_id,price,advance,royalty,ytd_sales,notes,pubdate)
values(6,'Oracle Principle','DATABASE','0002',18,0,1,200,'',getdate())
go
if exists (select * from sysobjects where name = 'publishers')
drop table publishers
go
create table publishers(
pub_id char(4) not null,
pub_name varchar(40) null,
city varchar(20) null,
state char(2) null,
country varchar(30) default 'USA' null
)
go
alter table publishers add constraint pk_publishers primary key(pub_id)
go
insert into publishers(pub_id,pub_name,city,state,country)
values('0001','机械出版社','北京','1','CHINA')
insert into publishers(pub_id,pub_name,city,state,country)
values('0002','New Moon Books','London','1','England')
go
二、SYBASE不支持的子查询
1、Sybase中不支持在FROM子句中使用子查询
sybase中不可以在from子句中使用子查询。
如:select * from (select * from a) t
解决方法是采用临时表、视图。
2、Sybase 不支持使用 TOP分页查询
在微软的Sql Server中,在其T-SQL中引入了top语法,通过该语法可以非常方便的实现分页查询,sql语句为(以Ctsi业务为例,IdCdr为话单表的唯一标识字段):
select top 每页记录数 * from CtsiInfoRecord01
where IdCdr not in
(select top 页数*每页记录数 IdCdr
from CtsiInfoRecord01
order by IdCdr)
order by IdCdr
在实际查询时,只需要修改子查询的top记录数即可。
遗憾的是,该top语法在sybase中并不支持。相对应的语法为set rowcount 记录数。但该语法不能放在子查询语句中,因此,上述的方法无法实现。
解决方案一:通过建立临时表结合分页查询
根据该方法的实现思路,引入临时表,并结合分页查询来实现,sql语句如下:
set rowcount页数*每页记录数
select IdCdr into #ctsitable from CtsiInfoRecord01 order by IdCdr
set rowcount 每页记录数
select * from CtsiInfoRecord01 where IdCdr not in
(select IdCdr from #ctsitable ) order by IdCdr
drop table #ctsitable
注:#ctsitable为临时库tempdb中的临时表;
在sybase中,不支持在子查询中引入order by;
如果查询第一页,则不需要建立临时表,直接查询即可:
set rowcount 每页记录数
select * from CtsiInfoRecord01 order by IdCdr
解决方案二:直接根据IdCdr条件分页查询
假定话单表的唯一标识字段为IdCdr。如果通过order by进行排序(默认升序),在每页记录数固定以及查询条件相同的前提下,下一页查询的所有记录,其IdCdr值必然大于上一页末记录的IdCdr。如果我们每次查询后,获得了末记录的IdCdr值,然后在下一次查询时,引入该条件,得到的结果必然是根据条件查询出来的下一页结果。方法如下:
set rowcount 每页记录数
select * from CtsiInfoRecord where IdCdr > 上一页末记录IdCdr值 order by IdCdr
如果是上一页查询,则刚好相反,需要获得下一页首记录的IdCdr值:
set rowcount 每页记录数
select * from CtsiInfoRecord where IdCdr < 下一页首记录IdCdr值
注:如果查询首页,则将IdCdr值条件删掉。
如果查询末页,在删掉IdCdr值条件的同时,将排序改为降序的方式。
三、总结
综上,SYBASE数据库支持使用exists、not exists、in、not in、having、比较运算符的子查询和相关子查询;SYBASE不支持在from子句中的子查询,不支持子查询内使用top和order by。我们不必再发出这样的叹息“SYBASE数据库不支持子查询”,掌握并合理使用各种数据库的特点,我们的工作会更加得心应手。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/liuzh501448/archive/2007/04/10/1559241.aspx