`

学习SQL应知道的动态SQL语句基本语法

阅读更多
学习SQL应知道的动态SQL语句基本语法
1 、普通SQL语句可以用Exec执行

eg: Select * from tableName 
Exec('select * from tableName') 
Exec sp_executesql N'select * from tableName' -- 请注意字符串前一定要加N 

2、字段名,表名,数据库名之类作为变量时,必须用动态SQL

eg: 
declare @fname varchar(20) 
set @fname = 'FiledName' 
Select @fname from tableName -- 错误,不会提示错误,但结果为固定值FiledName,并非所要。 
Exec('select ' + @fname + ' from tableName') -- 请注意 加号前后的 单引号的边上加空格 

当然将字符串改成变量的形式也可 
declare @fname varchar(20) 
set @fname = 'FiledName' --设置字段名 

declare @s varchar(1000) 
set @s = 'select ' + @fname + ' from tableName' 
Exec(@s) -- 成功 
exec sp_executesql @s -- 此句会报错 


declare @s Nvarchar(1000) -- 注意此处改为nvarchar(1000) 
set @s = 'select ' + @fname + ' from tableName' 
Exec(@s) -- 成功 
exec sp_executesql @s -- 此句正确 

3、输出参数

declare @num int, 
@sqls nvarchar(4000) 
set @sqls='select count(*) from tableName' 
exec(@sqls) 
--如何将exec执行结果放入变量中? 

declare @num int, 
@sqls nvarchar(4000) 
set @sqls='select @a=count(*) from tableName ' 
exec sp_executesql @sqls,N'@a int output',@num output 
select @num 

此外,如果想要在SQL语句 字符串中使用 单引号 '' 可以 使用 ''''

SQL Server数据库中经常用到的identity列

发布时间:2008.03.24 04:59     来源:赛迪网    作者:Alice
【赛迪网-IT技术报道】SQL Server中,经常会用到Identity标识列,这种自增长的字段操作起来的确是比较方便。但它有时还会带来一些麻烦。
示例一 :当表中被删除了某些数据的时候,自增长列的编号就不再是一个连线的数列。这种时候我们可以用以下方案来解决。
SET IDENTITY_INSERT  [ON|OFF]
允许将显式值插入表的标识列中,当设置为ON时,这时可能在INSERT操作时手工指定插入到标识列中的编号,同时必须在操作完成后,将IDENTITY_INSERT还原成OFF,否则下次插入的时候必须指定编号,那不然就无法完成INSERT操作。
示例二:当表中的记录被全部删除,但此时标识列的值越来越大的时候,如果不加以重置,它还会无休止的增长。这个时候我们就要用到:
DBCC CHECKIDENT(TABLE, [RESEED|NORESEED], [1])
将把指定表的种子值强制重设为1。然而,你可能不想将种子重设为1,在这种情况下,你可以用你想用的种子值替代第三个参数。有时候你可能想知道当前的种子,而不是想重设种子,这时你就要用到NORESEED,而不用再去顾忌第三个参数。





“一网打尽”通用SQL数据库的查询语句 (1)

发布时间:2008.01.04 04:40     来源:赛迪网    作者:20933
通用SQL数据库的查询语句:
(注释:本文中Transact-SQL查询只包括选择列表、FROM子句和WHERE子句。)
一、 简单查询
简单的Transact-SQL查询只包括选择列表、FROM子句和WHERE子句。它们分别说明所查询列、查询的表或视图、以及搜索条件等。
例如,下面的语句查询testtable表中姓名为“张三”的nickname字段和email字段。
SELECT   nickname,email

FROM   testtable

WHERE   name= '张三 '
(一) 选择列表
选择列表(select_list)指出所查询列,它可以是一组列名列表、星号、表达式、变量(包括局部变量和全局变量)等构成。
1、选择所有列
例如,下面语句显示testtable表中所有列的数据:
SELECT   *

FROM   testtable
2、选择部分列并指定它们的显示次序
查询结果集合中数据的排列顺序与选择列表中所指定的列名排列顺序相同。
例如:   SELECT   nickname,email

FROM   testtable
3、更改列标题
在选择列表中,可重新指定列标题。定义格式为:
列标题=列名
列名 列标题
如果指定的列标题不是标准的标识符格式时,应使用引号定界符,例如,下列语句使用汉字显示列标题:
SELECT   昵称=nickname,电子邮件=email

FROM   testtable

4、删除重复行
SELECT语句中使用ALL或DISTINCT选项来显示表中符合条件的所有行或删除其中重复的数据行,默认为ALL。使用DISTINCT选项时,对于所有重复的数据行在SELECT返回的结果集合中只保留一行。
5、限制返回的行数
使用TOP n [PERCENT]选项限制返回的数据行数,TOP n说明返回n行,而TOP n PERCENT时,说明n是表示一百分数,指定返回的行数等于总行数的百分之几。
例如:   SELECT   TOP   2   *FROM   testtable   SELECT  
TOP   20   PERCENT   *   FROM   testtable
(二)FROM子句
FROM子句指定SELECT语句查询及与查询相关的表或视图。在FROM子句中最多可指定256个表或视图,它们之间用逗号分隔。
在FROM子句同时指定多个表或视图时,如果选择列表中存在同名列,这时应使用对象名限定这些列所属的表或视图。例如在usertable和citytable表中同时存在cityid列,在查询两个表中的cityid时应使用下面语句格式加以限定:
SELECT   username,citytable.cityid

FROM   usertable,citytable

WHERE   usertable.cityid=citytable.cityid
在FROM子句中可用以下两种格式为表或视图指定别名:
表名 as 别名
表名 别名
例如上面语句可用表的别名格式表示为:
SELECT   username,b.cityid

FROM   usertable   a,citytable   b

WHERE   a.cityid=b.cityid
SELECT不仅能从表或视图中检索数据,它还能够从其它查询语句所返回的结果集合中查询数据。
例如:   SELECT   a.au_fname+a.au_lname

FROM   authors   a,titleauthor   ta

(SELECT   title_id,title

FROM   titles

WHERE   ytd_sales> 10000

)   AS   t

WHERE   a.au_id=ta.au_id

AND   ta.title_id=t.title_id
此例中,将SELECT返回的结果集合给予一别名t,然后再从中检索数据。
(三) 使用WHERE子句设置查询条件
WHERE子句设置查询条件,过滤掉不需要的数据行。例如下面语句查询年龄大于20的数据:
SELECT   *

FROM   usertable

WHERE   age> 20
WHERE子句可包括各种条件运算符:
比较运算符(大小比较):> 、> =、=、 <、 <=、 <> 、!> 、! <
范围运算符(表达式值是否在指定的范围):BETWEEN…AND…
NOT BETWEEN…AND…
列表运算符(判断表达式是否为列表中的指定项):IN (项1,项2……)
NOT IN (项1,项2……)
模式匹配符(判断值是否与指定的字符通配格式相符):LIKE、NOT LIKE
空值判断符(判断表达式是否为空):IS NULL、NOT IS NULL
逻辑运算符(用于多条件的逻辑连接):NOT、AND、OR
1、范围运算符例:age BETWEEN 10 AND 30相当于age> =10 AND age <=30
2、列表运算符例:country IN ( 'Germany ', 'China ')
3、模式匹配符例:常用于模糊查找,它判断列值是否与指定的字符串格式相匹配。可用于char、varchar、text、ntext、datetime和smalldatetime等类型查询。
可使用以下通配字符:
百分号%:可匹配任意类型和长度的字符,如果是中文,请使用两个百分号即%%。
下划线_:匹配单个任意字符,它常用来限制表达式的字符长度。
方括号[]:指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个。[^]:其取值也[] 相同,但它要求所匹配对象为指定字符以外的任一个字符。
例如:
限制以Publishing结尾,使用LIKE '%Publishing '
限制以A开头:LIKE '[A]% '
限制以A开头外:LIKE '[^A]% '
4、空值判断符例WHERE age IS NULL
5、逻辑运算符:优先级为NOT、AND、OR
(四)查询结果排序
使用ORDER BY子句对查询返回的结果按一列或多列排序。ORDER BY子句的语法格式为:
ORDER   BY   {column_name   [ASC &brvbar;DESC]}   [,…n]
其中ASC表示升序,为默认值,DESC为降序。ORDER BY不能按ntext、text和image数据类型进行排序。
例如:   SELECT   *

FROM   usertable

ORDER   BY   age   desc,userid   ASC
另外,可以根据表达式进行排序。
二、 联合查询
UNION运算符可以将两个或两个以上上SELECT语句的查询结果集合合并成一个结果集合显示,即执行联合查询。UNION的语法格式为:
select_statement

UNION   [ALL]   selectstatement

[UNION   [ALL]   selectstatement][…n]
其中selectstatement为待联合的SELECT查询语句。
ALL选项表示将所有行合并到结果集合中。不指定该项时,被联合查询结果集合中的重复行将只保留一行。
联合查询时,查询结果的列标题为第一个查询语句的列标题。因此,要定义列标题必须在第一个查询语句中定义。要对联合查询结果排序时,也必须使用第一查询语句中的列名、列标题或者列序号。
在使用UNION 运算符时,应保证每个联合查询语句的选择列表中有相同数量的表达式,并且每个查询选择表达式应具有相同的数据类型,或是可以自动将它们转换为相同的数据类型。在自动转换时,对于数值类型,系统将低精度的数据类型转换为高精度的数据类型。
在包括多个查询的UNION语句中,其执行顺序是自左至右,使用括号可以改变这一执行顺序。例如:
查询1 UNION (查询2 UNION 查询3)
三、连接查询
通过连接运算符可以实现多个表查询。连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志。
在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中。当检索数据时,通过连接操作查询出存放在多个表中的不同实体的信息。连接操作给用户带来很大的灵活性,他们可以在任何时候增加新的数据类型。为不同实体创建新的表,尔后通过连接进行查询。
连接可以在SELECT 语句的FROM子句或WHERE子句中建立,似是而非在FROM子句中指出连接时有助于将连接操作与WHERE子句中的搜索条件区分开来。所以,在Transact-SQL中推荐使用这种方法。
SQL-92标准所定义的FROM子句的连接语法格式为:
FROM   join_table   join_type   join_table

[ON   (join_condition)]
其中join_table指出参与连接操作的表名,连接可以对同一个表操作,也可以对多表操作,对同一个表操作的连接又称做自连接。
join_type 指出连接类型,可分为三种:内连接、外连接和交叉连接。内连接(INNER JOIN)使用比较运算符进行表间某(些)列数据的比较操作,并列出这些表中与连接条件相匹配的数据行。根据所使用的比较方式不同,内连接又分为等值连接、自然连接和不等连接三种。外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN)、右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接(FULL OUTER JOIN或FULL JOIN)三种。与内连接不同的是,外连接不只列出与连接条件相匹配的行,而是列出左表(左外连接时)、右表(右外连接时)或两个表(全外连接时)中所有符合搜索条件的数据行。
交叉连接(CROSS JOIN)没有WHERE 子句,它返回连接表中所有数据行的笛卡尔积,其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
连接操作中的ON (join_condition) 子句指出连接条件,它由被连接表中的列和比较运算符、逻辑运算符等构成。
无论哪种连接都不能对text、ntext和image数据类型列进行直接连接,但可以对这三种列进行间接连接。例如:
SELECT   p1.pub_id,p2.pub_id,p1.pr_info

FROM   pub_info   AS   p1   INNER   JOIN   pub_info   AS   p2

ON   DATALENGTH(p1.pr_info)=DATALENGTH(p2.pr_info)
(一)内连接
内连接查询操作列出与连接条件匹配的数据行,它使用比较运算符比较被连接列的列值。内连接分三种:
1、等值连接:在连接条件中使用等于号(=)运算符比较被连接列的列值,其查询结果中列出被连接表中的所有列,包括其中的重复列。
2、不等连接: 在连接条件使用除等于运算符以外的其它比较运算符比较被连接的列的列值。这些运算符包括> 、> =、 <=、 <、!> 、! <和 <> 。
3、自然连接:在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。
例,下面使用等值连接列出authors和publishers表中位于同一城市的作者和出版社:
SELECT   *

FROM   authors   AS   a   INNER   JOIN   publishers   AS   p

ON   a.city=p.city
又如使用自然连接,在选择列表中删除authors 和publishers 表中重复列(city和state):
SELECT   a.*,p.pub_id,p.pub_name,p.country

FROM   authors   AS   a   INNER   JOIN   publishers   AS   p

ON   a.city=p.city
(二)外连接
内连接时,返回查询结果集合中的仅是符合查询条件( WHERE 搜索条件或 HAVING 条件)和连接条件的行。而采用外连接时,它返回到查询结果集合中的不仅包含符合连接条件的行,而且还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。如下面使用左外连接将论坛内容和作者信息连接起来:
SELECT   a.*,b.*   FROM   luntan   LEFT   JOIN   usertable   as   b

ON   a.username=b.username
下面使用全外连接将city表中的所有作者以及user表中的所有作者,以及他们所在的城市:
SELECT   a.*,b.*

FROM   city   as   a   FULL   OUTER   JOIN   user   as   b

ON   a.username=b.username
(三)交叉连接
交叉连接不带WHERE 子句,它返回被连接的两个表所有数据行的笛卡尔积,返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。例,titles表中有6类图书,而publishers表中有8家出版社,则下列交叉连接检索到的记录数将等。
于6*8=48行。   SELECT   type,pub_name

FROM   titles   CROSS   JOIN   publishers

ORDER   BY   type

[Post=0][/Post]





教你快速掌握一些异常精妙的"SQL"语句

发布时间:2008.03.11 04:58     来源:赛迪网    作者:钱海歌
【赛迪网-IT技术报道】精妙的"SQL"语句:
◆复制表(只复制结构,源表名:a 新表名:b)
SQL: select * into b from a where 1<>1
  
◆拷贝表(拷贝数据,源表名:a 目标表名:b)
SQL: insert into b(a, b, c) select d,e,f from b;  
◆显示文章、提交人和最后回复时间
SQL: select a.title,a.username,b.adddate from table a,

(select max(adddate) adddate from table where table.title=a.title) b  
◆说明:外连接查询(表名1:a 表名2:b)
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a =

b.c
◆日程安排提前五分钟提醒
SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5   
◆两张关联表,删除主表中已经在副表中没有的信息
SQL:

delete from info where not exists
( select * from infobz where info.infid=infobz.infid )
◆说明:
SQL:

SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE
FROM TABLE1,(SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE
PREV_UPD_DATE FROM (SELECT NUM, UPD_DATE, INBOUND_QTY,
STOCK_ONHAND FROM TABLE2 WHERE TO_CHAR(UPD_DATE,
'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X,
(SELECT NUM, UPD_DATE, STOCK_ONHAND FROM TABLE2
WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(TO_DATE
(TO_CHAR(SYSDATE, 'YYYY/MM') &brvbar;&brvbar; '/01','
YYYY/MM/DD') - 1, 'YYYY/MM') ) Y, WHERE X.NUM = Y.NUM
(+)AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) <>
X.STOCK_ONHAND ) B WHERE A.NUM = B.NUM
  
◆说明:
SQL:

select * from studentinfo where not exists(select * from student where

studentinfo.id=student.id) and 系名称='"&strdepartmentname&"' and 专业名称

='"&strprofessionname&"' order by 性别,生源地,高考总成绩

实例讲解SQL Server中"Update"的用法

发布时间:2008.02.28 05:07     来源:赛迪网    作者:Alizze
SQL Server中"Update"的用法:
例子:
在表中有两个字段:id_no (varchar) , in_date (datetime) ,把in_date相同的记录的in_date依次累加1秒, 使in_date没有相同的记录。
以下为原始的数据:
id_no         in_date
5791 2003-9-1   14:42:02
5792 2003-9-1   14:42:02
5794 2003-9-1   14:42:02
5795 2003-9-1   14:42:03
5796 2003-9-1   14:42:03
5797 2003-9-1   14:42:03
5831 2003-9-1   14:42:04
5832 2003-9-1   14:42:14
5833 2003-9-1   14:42:14
结果为:
id_no         in_date
5791 2003-9-1   14:42:02
5792 2003-9-1   14:42:03
5794 2003-9-1   14:42:04
5795 2003-9-1   14:42:05
5796 2003-9-1   14:42:06
5797 2003-9-1   14:42:07
5831 2003-9-1   14:42:08
5832 2003-9-1   14:42:14
5833 2003-9-1   14:42:15
处理的方法:
--建立测试环境
create table a(id_no varchar(8),in_date datetime)
go
insert into a select '5791','2003-9-1 14:42:02'
union all select '5792','2003-9-1 14:42:02'
union all select '5794','2003-9-1 14:42:02'
union all select '5795','2003-9-1 14:42:03'
union all select '5796','2003-9-1 14:42:03'
union all select '5797','2003-9-1 14:42:03'
union all select '5831','2003-9-1 14:42:04'
union all select '5832','2003-9-1 14:42:04'
union all select '5833','2003-9-1 14:42:04'
union all select '5734','2003-9-1 14:42:02'
union all select '6792','2003-9-1 14:42:22'
union all select '6794','2003-9-1 14:42:22'
union all select '6795','2003-9-1 14:42:23'
union all select '6796','2003-9-1 14:42:23'
union all select '6797','2003-9-1 14:42:23'
union all select '6831','2003-9-1 14:42:34'
union all select '6832','2003-9-1 14:42:34'
union all select '6833','2003-9-1 14:42:54'
union all select '6734','2003-9-1 14:42:22'
go
--生成临时表,按照in_date排序
select * into # from a order by in_date
--相同的时间,加一秒。加完了不带重复的
declare @date1 datetime,@date2 datetime,@date datetime
update #
  set @date=case when @date1=in_date or @date2>=in_date
then dateadd(s,1,@date2) else in_date end,
      @date1=in_date,
      @date2=@date,
      in_date=@date
--更新到基本表中去
update a set a.in_date=b.in_date from
a a join # b on a.id_no=b.id_no

select * from a
drop table #,a


三种数据库利用SQL语句进行高效果分页

发布时间:2008.01.21 04:50     来源:赛迪网    作者:10687
在程序的开发过程中,处理分页是大家接触比较频繁的事件,因为现在软件基本上都是与数据库进行挂钓的。但效率又是我们所追求的,如果是像原来那样把所有满足条件的记录全部都选择出来,再去进行分页处理,那么就会多多的浪费掉许多的系统处理时间。为了能够把效率提高,所以现在我们就只选择我们需要的数据,减少数据库的处理时间,以下就是常用SQL分页处理:
1、SQL Server、Access数据库
这都微软的数据库,都是一家人,基本的操作都是差不多,常采用如下分页语句:
PAGESIZE:每页显示的记录数
CURRENTPAGE:当前页号
数据表的名字是:components
索引主键字是:id
select top PAGESIZE * from components where id not in
(select top (PAGESIZE*(CURRENTPAGE-1))
id from components order by id)order by id
如下列:
select top 10 * from components where id not in
(select top 10*10 id from components order by id)
order by id
从101条记录开始选择,只选择前面的10条记录
2、Oracle数据库
因为Oracle数据库没有Top关键字,所以这里就不能够像微软的数据据那样操作,这里有两种方法:
(1)、一种是利用相反的。
PAGESIZE:每页显示的记录数
CURRENTPAGE:当前页号
数据表的名字是:components
索引主键字是:id
select * from components where id not
in(select id from components where               
rownum<=(PAGESIZE*(CURRENTPAGE-1)))
and rownum<=PAGESIZE order by id;
如下例:
select * from components where id not in
(select id from components where rownum<=100)
and rownum<=10 order by id;
从101到记录开始选择,选择前面10条。
(2)、使用minus,即中文的意思就是减去。
select * from components where rownum
<=(PAGESIZE*(CURRENTPAGE-1)) minus
select * from components where rownum
<=(PAGESIZE*(CURRENTPAGE-2));
如例:select * from components where
rownum<=10 minus select * from components
where rownum<=5;.
(3)、一种是利用Oracle的rownum,这个是Oracle查询自动返回的序号,一般不显示,但是可以通过select rownum from [表名]看到,注意,它是从1到当前的记录总数。
select * from (select rownum tid,components.
* from components where rownum<=100) where tid<=10;

深入讲解SQL Server数据库的嵌套子查询

发布时间:2008.02.02 05:05     来源:赛迪网    作者:Liulian
很多人对子查询(subqueries)的使用都感到很迷惑,尤其对于嵌套子查询(即子查询中包含一个子查询)。现在,就让我们追本溯源地探究这个问题。
有两种子查询类型:标准和相关。标准子查询执行一次,结果反馈给父查询。相关子查询每行执行一次,由父查询找回。在本文中,我将重点讨论嵌套子查询(nested subqueries)(我将在以后介绍相关子查询)。
试想这个问题:你想生成一个卖平垫圈的销售人员列表。你需要的数据分散在四个表格中:人员.联系方式(Person.Contact),人力资源.员工(HumanResources.Employee),销售.销售订单标题(Sales.SalesOrderHeader),销售.销售订单详情(Sales.SalesOrderDetail)。在SQL Server中,你从内压式(outside-in)写程序,但从外压式(inside-out)开始考虑非常有帮助,即可以一次解决需要的一个语句。
如果从内到外写起,可以检查Sales.SalesOrderDetail表格,在LIKE语句中匹配产品数(ProductNumber)值。你将这些行与Sales.SalesOrderHeader表格连接,从中可以获得销售人员IDs(SalesPersonIDs)。然后使用SalesPersonID连接SalesPersonID表格。最后,使用ContactID连接Person.Contact表格。
USE AdventureWorks ;

GO

SELECT DISTINCT c.LastName, c.FirstName

FROM Person.Contact c JOIN HumanResources.Employee e

ON e.ContactID = c.ContactID WHERE EmployeeID IN

(SELECT SalesPersonID

FROM Sales.SalesOrderHeader

WHERE SalesOrderID IN

(SELECT SalesOrderID

FROM Sales.SalesOrderDetail

WHERE ProductID IN

(SELECT ProductID

FROM Production.Product p

WHERE ProductNumber LIKE'FW%')));

GO
这个例子揭示了有关SQL Server的几个绝妙事情。你可以发现,可以用IN()参数替代SELECT 语句。在本例中,有两次应用,因此创建了一个嵌套子查询。
我是标准化(normalization)的发烧友,尽管我不接受其荒谬的长度。由于标准化具有各种查询而增加了复杂性。在这些情况下子查询就显得非常有用,嵌套子查询甚至更加有用。
当你需要的问题分散于很多表格中时,你必须再次将它们拼在一起,这时你可能发现嵌套子程序就很有用。
使用SQL视图查出所有的数据库字典

发布时间:2008.01.07 09:15     来源:赛迪网    作者:20936
本文中的SQL代码可以在企业管理器、查询分析器中简单执行,直接了当的查出SQL Server 2000及SQL Server 2005的所有数据字典。
(注释:数据库字典包括表结构(分SQL Server 2000和SQL Server 2005)、索引和主键.外键.约束.视图.函数.存储过程.触发器。)
SQL Server 2000数据库字典—表结构.sql
SELECT TOP 100 PERCENT --a.id,
      CASE WHEN a.colorder = 1 THEN d.name ELSE '' END AS 表名,
      CASE WHEN a.colorder = 1 THEN isnull(f.value, '') ELSE '' END AS 表说明,
      a.colorder AS 字段序号, a.name AS 字段名, CASE WHEN COLUMNPROPERTY(a.id,
      a.name, 'IsIdentity') = 1 THEN '√' ELSE '' END AS 标识,
      CASE WHEN EXISTS
          (SELECT 1
         FROM dbo.sysindexes si INNER JOIN
               dbo.sysindexkeys sik ON si.id = sik.id AND si.indid = sik.indid INNER JOIN
               dbo.syscolumns sc ON sc.id = sik.id AND sc.colid = sik.colid INNER JOIN
               dbo.sysobjects so ON so.name = si.name AND so.xtype = 'PK'
         WHERE sc.id = a.id AND sc.colid = a.colid) THEN '√' ELSE '' END AS 主键,
      b.name AS 类型, a.length AS 长度, COLUMNPROPERTY(a.id, a.name, 'PRECISION')
      AS 精度, ISNULL(COLUMNPROPERTY(a.id, a.name, 'Scale'), 0) AS 小数位数,
      CASE WHEN a.isnullable = 1 THEN '√' ELSE '' END AS 允许空, ISNULL(e.text, '')
      AS 默认值, ISNULL(g.[value], '') AS 字段说明, d.crdate AS 创建时间,
      CASE WHEN a.colorder = 1 THEN d.refdate ELSE NULL END AS 更改时间
FROM dbo.syscolumns a LEFT OUTER JOIN
      dbo.systypes b ON a.xtype = b.xusertype INNER JOIN
      dbo.sysobjects d ON a.id = d.id AND d.xtype = 'U' AND
      d.status >= 0 LEFT OUTER JOIN
      dbo.syscomments e ON a.cdefault = e.id LEFT OUTER JOIN
      dbo.sysproperties g ON a.id = g.id AND a.colid = g.smallid AND
      g.name = 'MS_Description' LEFT OUTER JOIN
      dbo.sysproperties f ON d.id = f.id AND f.smallid = 0 AND
      f.name = 'MS_Description'
ORDER BY d.name, a.colorder
SQL Server 2005数据库字典--表结构.sql
SELECT TOP 100 PERCENT --a.id,
      CASE WHEN a.colorder = 1 THEN d.name ELSE '' END AS 表名,
      CASE WHEN a.colorder = 1 THEN isnull(f.value, '') ELSE '' END AS 表说明,
      a.colorder AS 字段序号, a.name AS 字段名, CASE WHEN COLUMNPROPERTY(a.id,
      a.name, 'IsIdentity') = 1 THEN '√' ELSE '' END AS 标识,
      CASE WHEN EXISTS
          (SELECT 1
         FROM dbo.sysindexes si INNER JOIN
               dbo.sysindexkeys sik ON si.id = sik.id AND si.indid = sik.indid INNER JOIN
               dbo.syscolumns sc ON sc.id = sik.id AND sc.colid = sik.colid INNER JOIN
               dbo.sysobjects so ON so.name = si.name AND so.xtype = 'PK'
         WHERE sc.id = a.id AND sc.colid = a.colid) THEN '√' ELSE '' END AS 主键,
      b.name AS 类型, a.length AS 长度, COLUMNPROPERTY(a.id, a.name, 'PRECISION')
      AS 精度, ISNULL(COLUMNPROPERTY(a.id, a.name, 'Scale'), 0) AS 小数位数,
      CASE WHEN a.isnullable = 1 THEN '√' ELSE '' END AS 允许空, ISNULL(e.text, '')
      AS 默认值, ISNULL(g.[value], '') AS 字段说明, d.crdate AS 创建时间,
      CASE WHEN a.colorder = 1 THEN d.refdate ELSE NULL END AS 更改时间
FROM dbo.syscolumns a LEFT OUTER JOIN
      dbo.systypes b ON a.xtype = b.xusertype INNER JOIN
      dbo.sysobjects d ON a.id = d.id AND d.xtype = 'U' AND
      d.status >= 0 LEFT OUTER JOIN
      dbo.syscomments e ON a.cdefault = e.id LEFT OUTER JOIN
      dbo.sysproperties g ON a.id = g.id AND a.colid = g.smallid AND
      g.name = 'MS_Description' LEFT OUTER JOIN
      dbo.sysproperties f ON d.id = f.id AND f.smallid = 0 AND
      f.name = 'MS_Description'
ORDER BY d.name, a.colorder
SQL Server数据库字典--索引.sql
SELECT TOP 100 PERCENT --a.id,
      CASE WHEN b.keyno = 1 THEN c.name ELSE '' END AS 表名,
      CASE WHEN b.keyno = 1 THEN a.name ELSE '' END AS 索引名称, d.name AS 列名,
      b.keyno AS 索引顺序, CASE indexkey_property(c.id, b.indid, b.keyno, 'isdescending')
      WHEN 1 THEN '降序' WHEN 0 THEN '升序' END AS 排序, CASE WHEN p.id IS NULL
      THEN '' ELSE '√' END AS 主键, CASE INDEXPROPERTY(c.id, a.name, 'IsClustered')
      WHEN 1 THEN '√' WHEN 0 THEN '' END AS 聚集, CASE INDEXPROPERTY(c.id,
      a.name, 'IsUnique') WHEN 1 THEN '√' WHEN 0 THEN '' END AS 唯一,
      CASE WHEN e.id IS NULL THEN '' ELSE '√' END AS 唯一约束,
      a.OrigFillFactor AS 填充因子, c.crdate AS 创建时间, c.refdate AS 更改时间
FROM dbo.sysindexes a INNER JOIN
      dbo.sysindexkeys b ON a.id = b.id AND a.indid = b.indid INNER JOIN
      dbo.syscolumns d ON b.id = d.id AND b.colid = d.colid INNER JOIN
      dbo.sysobjects c ON a.id = c.id AND c.xtype = 'U' LEFT OUTER JOIN
      dbo.sysobjects e ON e.name = a.name AND e.xtype = 'UQ' LEFT OUTER JOIN
      dbo.sysobjects p ON p.name = a.name AND p.xtype = 'PK'
WHERE (OBJECTPROPERTY(a.id, N'IsUserTable') = 1) AND (OBJECTPROPERTY(a.id,
      N'IsMSShipped') = 0) AND (INDEXPROPERTY(a.id, a.name, 'IsAutoStatistics') = 0)
ORDER BY c.name, a.name, b.keyno
SQL Server数据库字典--主键.外键.约束.视图.函数.存储过程.触发器.sql
SELECT DISTINCT
      TOP 100 PERCENT o.xtype,
      CASE o.xtype WHEN 'X' THEN '扩展存储过程' WHEN 'TR' THEN '触发器' WHEN 'PK' THEN
       '主键' WHEN 'F' THEN '外键' WHEN 'C' THEN '约束' WHEN 'V' THEN '视图' WHEN 'FN'
       THEN '函数-标量' WHEN 'IF' THEN '函数-内嵌' WHEN 'TF' THEN '函数-表值' ELSE '存储过程'
       END AS 类型, o.name AS 对象名, o.crdate AS 创建时间, o.refdate AS 更改时间,
      c.text AS 声明语句
FROM dbo.sysobjects o LEFT OUTER JOIN
      dbo.syscomments c ON o.id = c.id
WHERE (o.xtype IN ('X', 'TR', 'C', 'V', 'F', 'IF', 'TF', 'FN', 'P', 'PK')) AND
      (OBJECTPROPERTY(o.id, N'IsMSShipped') = 0)
ORDER BY CASE o.xtype WHEN 'X' THEN '扩展存储过程' WHEN 'TR' THEN '触发器' WHEN
       'PK' THEN '主键' WHEN 'F' THEN '外键' WHEN 'C' THEN '约束' WHEN 'V' THEN '视图'
       WHEN 'FN' THEN '函数-标量' WHEN 'IF' THEN '函数-内嵌' WHEN 'TF' THEN '函数-表值'
       ELSE '存储过程' END DESC

两个表间不存在的insert与存在的update

发布时间:2008.02.29 05:07     来源:赛迪网    作者:Alice
两个表间,不存在的insert与存在的update示例:
IF OBJECT_ID('dbo.sp_showtable_insert') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.sp_showtable_insert
IF OBJECT_ID('dbo.sp_showtable_insert') IS NOT NULL
PRINT '<<< FAILED DROPPING PROCEDURE dbo.sp_showtable_insert >>>'
ELSE
PRINT '<<< DROPPED PROCEDURE dbo.sp_showtable_insert >>>'
END
go
SET ANSI_NULLS ON
go
SET QUOTED_IDENTIFIER ON
go

create procedure [dbo].[sp_showtable_insert]
@tablename1 varchar(100), @tablename2 varchar(100)
as
begin
DECLARE @MAX_ID NUMERIC(18,0)
DECLARE @MAX_ID2 NUMERIC(18,0)
create table #ins_tab(fg int,col_name1
nvarchar(150),col_name_val nvarchar(150),col_name2
nvarchar(150),colid numeric(18,0))
insert into #ins_tab(fg,col_name1,col_name_val,colid) values(0,'INSERT

INTO '+@tablename1,'',10)

insert into #ins_tab(fg,col_name1,col_name_val) values(1,'(','')

insert into #ins_tab(fg,col_name1,col_name_val,colid)

select 2,b.name,'/*'+b.name+'_Value*/',b.colid
from sysobjects a ,syscolumns b
where a.name=@tablename1
and a.id=b.id
and a.type='U'

insert into #ins_tab(fg,col_name1,col_name_val) values(3,')','')

insert into #ins_tab(fg,col_name1,col_name_val) values(4,'SELECT ','')

insert into #ins_tab(fg,col_name1,col_name_val,colid)
select 5,'--'+b.name,b.name,b.colid
from sysobjects a ,syscolumns b
where a.name=@tablename2
and a.id=b.id
and a.type='U'


update #ins_tab
set col_name2=b.name
from sysobjects a ,syscolumns b,#ins_tab c
where a.name=@tablename2
and a.id=b.id
and a.type='U'
and c.col_name1=b.name
and c.fg=2

update #ins_tab
set col_name_val= CASE when isnull(col_name2,'1')

='1' THEN 'null'+col_name_val else col_name2+col_name_val end
where fg=2



delete #ins_tab
from #ins_tab a
where a.fg=5
and exists(select 1
from #ins_tab b
where b.col_name1=a.col_name_val
and b.fg=2)

insert into #ins_tab(fg,col_name1,col_name_val,colid)
values(6,'FROM '+@tablename2,'',10)

insert into #ins_tab(fg,col_name1,col_name_val,colid) values(7,'UPDATE '+@tablename1,'',10)
insert into #ins_tab(fg,col_name1,col_name_val) values(8,' SET ','')
insert into #ins_tab(fg,col_name1,col_name_val,colid)
SELECT 9,' '+substring(@tablename1+'.'+col_name1+' ',1,60)+'='+@tablename2+'.'+col_name1,'',colid
FROM #ins_tab where fg=2 AND isnull(col_name2,'1')<>'1'

insert into #ins_tab(fg,col_name1,col_name_val)
SELECT 10,' FROM '+@tablename1+','+@tablename2,''

insert into #ins_tab(fg,col_name1,col_name_val)
SELECT 11,'WHERE '+@tablename1+'.='+@tablename2+'.',''


SELECT @MAX_ID=MAX(colid) from #ins_tab where fg=2

select 0 AS FG,'-- INSERT '+@tablename1+' FROM '+@tablename2,0 AS colid
union
select fg,col_name1,colid from #ins_tab where fg=0
union
select fg,col_name1,colid from #ins_tab where fg=1
union
select fg,CASE WHEN colid=@MAX_ID THEN ' '
+col_name1 ELSE ' '+col_name1+',' END AS col_name1,
colid from #ins_tab where fg=2
union
select fg,col_name1,colid from #ins_tab where fg=3
union
select fg,col_name1,colid from #ins_tab where fg=4
union
select 5 as fg,CASE WHEN colid=@MAX_ID THEN ' '
+col_name_val ELSE ' '+col_name_val+',' END AS
col_name1,colid from #ins_tab where fg=2
union
select 6 as fg,col_name1,colid from #ins_tab where fg=6

union

select 6 AS FG,'WHERE NOT EXISTS(SELECT 1 FROM '+@tablename1+'

WHERE '+@tablename1+'.='+@tablename2+'.',21 AS colid
union
select 8 AS FG,'-- UPDATE '+@tablename1+' FROM '+@tablename2,0 AS colid
UNION
select 7 as fg,col_name1,colid from #ins_tab where fg=5
--UPDATE
union
select 8 as fg,col_name1,colid from #ins_tab where fg=7
union
select 9 as fg,col_name1,colid from #ins_tab where fg=8
union
select 10 as fg,CASE WHEN colid=@MAX_ID
THEN col_name1 ELSE col_name1+',' END AS col_name1,
colid from #ins_tab where fg=9
union
select 11 as fg,col_name1,colid from #ins_tab where fg=10
union
select 12 as fg,col_name1,colid from #ins_tab where fg=11
union
select 13 as fg,col_name1,colid from #ins_tab where fg=12

order by fg,colid
drop table #ins_tab
end

go
SET ANSI_NULLS OFF
go
SET QUOTED_IDENTIFIER OFF
go
IF OBJECT_ID('dbo.sp_showtable_insert') IS NOT NULL
PRINT '<<< CREATED PROCEDURE dbo.sp_showtable_insert >>>'
ELSE
PRINT '<<< FAILED CREATING PROCEDURE dbo.sp_showtable_insert >>>'
go

实现跨多个表格的数据进行组合的SQL语句 (1)

发布时间:2008.01.25 07:38     来源:赛迪网    作者:武西
在对跨多个表格的数据进行组合时,有时很难搞清楚要使用哪一个SQL句法。我将在这里对将多个表格中的查询合并至单一声明中的常用方式进行阐述。
在这篇文章中的样本查询符合SQL92 ISO标准。不是所有的数据库生产商都遵循这项标准,而且很多厂商采取的提升措施会带来一些意料不到的后果。如果你不确定你的数据库是不是支持这些标准,你可以参看生产厂商的有关资料。
SELECT
一个简单的SELECT声明就是查询多个表格的最基本的方式。你可以在FROM子句中调用多个表格来组合来自多个表格的结果。这里是一个它如何工作的实例:
以下为引用的内容:
SELECT table1.column1, table2.column2 FROM table1,

table2 WHERE table1.column1 = table2.column1;
这个实例中,我使用点号(table1.column1)来指定专栏来自哪一个表格。如果所涉及的专栏只在一个参考的表格中出现,你就不需要加入完整的名称,但是加入完整名称会对可读性起到帮助。
在FROM子句中表格之间由逗号来分隔,你可以加入所需的任意多的表格,尽管一些数据库有一个在引入正式的JOIN声明之前他们可以有效地处理的内容这方面的限制,这个将在下面谈到。
这个句法是一个简单的INNER JOIN。一些数据库将它看成与一个外部的JOIN是等同的。WHERE子句告知数据库哪一个区域要做关联,而且它返回结果时,就像列出的表格在给定的条件下组合成一个单独的表格一样。值得注意的是,你的比较条件并不需要与你作为结果组返回的专栏相同。在上面的例子中,table1.column1和table2.column1用来组合表格,但是返回的却是table2.column2。
你可以在WHERE子句中使用AND关键字来将这个功能扩展至多于两个的表格。你还可以使用这样的表格组合来限制你的结果而不用实际地从每个表格返回专栏。在下面的例子中,table3与table1匹配,但是我没有从table3返回任何东西来显示。我只是确保来自table1的有关专栏存在于table3之中。注意此例中table3需要在FROM子句中被引用。
以下为引用的内容:
SELECT table1.column1, table2.column2 FROM table1,

table2, table3 WHERE table1.column1 =

table2.column1 AND table1.column1 = table3.column1;
然而,要注意的是,这个查询多个表格的方式是一个暗指的JOIN。你的数据库可能对事物进行不同的处理,这取决于它所使用的优化引擎。而且,忽略对与WHERE子句的相关特性的定义将会给你带来不愿看到的结果,例如从余下的查询中返回与每一个可能的结果相关的专栏的rogue域,就像在CROSS JOIN之中一样。
如果你习惯于你的数据库处理这种类型的声明的方式,且你只对两个或是少数几个表格进行组合,一个简单的SELECT声明就可以达到目的。
JOIN
JOIN的工作方式与SELECT声明是相同的,它从不同的表格中返回一个带有专栏的结果组。在暗含的JOIN之上使用外部JOIN的优势是对你的结果组的更好的控制,而且还可能在涉及很多个表格的情况下提升性能表现。
JOIN的类型有几种:LEFT,RIGHT,FULL OUTER,INNER和CROSS。你所使用的类型是由你想要看到的结果所决定的。例如,使用LEFT OUTER JOIN将会从列出的第一个表格中返回所有有关的行,而同时如果没有信息与第一个表格相关的话将潜在地从所列出的第二个表格中加入行。
在这里INNER JOIN和暗含的JOIN是不同的,INNER JOIN将只返回那些在两个表格中都有数据的行。
对第一个SELECT查询使用如下JOIN声明:
以下为引用的内容:
SELECT table1.column1, table2.column2 FROM table1 INNER JOIN table2

ON table1.column1 = table2.column1;
子查询
子查询,或叫子选择声明,是在一个查询中将结果组作为资源使用的一个途径。他经常被用来对结果进行限制或定义,而不是运行多个查询或操纵应用软件之中的数据。有了子查询,你可以参考表格来决定数据的内含,或是在一些情况下,返回一个专栏,而这个专栏是一个子选择的结果。
下面的例子中使用了两个表格。一个表格中包含了我想要返回的数据,而另一个表格则给出一个比较点来确定什么数据是我确实感兴趣的。
以下为引用的内容:
SELECT column1 FROM table1 WHERE EXISTS

( SELECT column1 FROM table2

WHERE table1.column1 = table2.column1 );
子查询很重要的一个方面就是性能表现。便利性是有代价的,它取决于你所使用的表格和声明的大小,数量和复杂性,还有你可能会允许你的应用软件做处理工作。每一个查询在被主查询作为资源使用之前,都将被完整地单独处理。如果可能的话,创造性地使用JOIN声明可以以较少的滞后时间提供出相同的信息。 (责任编辑:卢兆林)
深入讲解SQL Union和Union All的使用方法

发布时间:2008.03.19 04:41     来源:赛迪网    作者:李思
【赛迪网-IT技术报道】UNION指令的目的是将两个SQL语句的结果合并起来。从这个角度来看, 我们会产生这样的感觉,UNION跟JOIN似乎有些许类似,因为这两个指令都可以由多个表格中撷取资料。 UNION的一个限制是两个 SQL 语句所产生的栏位需要是同样的资料种类。另外,当我们用 UNION这个指令时,我们只会看到不同的资料值 (类似 SELECT DISTINCT)。 union只是将两个结果联结起来一起显示,并不是联结两个表……
UNION 的语法如下: [SQL 语句 1]
UNION
[SQL 语句 2] 假设我们有以下的两个表格,  
Store_Information 表格   store_name  Sales  Date 
Los Angeles  $1500  Jan-05-1999 
San Diego  $250  Jan-07-1999 
Los Angeles  $300  Jan-08-1999 
Boston  $700  Jan-08-1999

Internet Sales 表格   Date  Sales 
Jan-07-1999  $250 
Jan-10-1999  $535 
Jan-11-1999  $320 
Jan-12-1999  $750
而我们要找出来所有有营业额 (sales) 的日子。要达到这个目的,我们用以下的 SQL 语句:
SELECT Date FROM Store_Information
UNION
SELECT Date FROM Internet_Sales 结果:  
Date 
Jan-05-1999 
Jan-07-1999 
Jan-08-1999 
Jan-10-1999 
Jan-11-1999 
Jan-12-1999
有一点值得注意的是,如果我们在任何一个 SQL 语句 (或是两句都一起) 用 "SELECT DISTINCT Date" 的话,那我们会得到完全一样的结果。
SQL Union All
UNION ALL 这个指令的目的也是要将两个 SQL 语句的结果合并在一起。 UNION ALL 和 UNION 不同之处在于 UNION ALL 会将每一笔符合条件的资料都列出来,无论资料值有无重复。 UNION ALL 的语法如下: [SQL 语句 1]
UNION ALL
[SQL 语句 2] 我们用和上一页同样的例子来显示出 UNION ALL 和 UNION 的不同。同样假设我们有以下两个表格:
Store_Information 表格   store_name  Sales  Date 
Los Angeles  $1500  Jan-05-1999 
San Diego  $250  Jan-07-1999 
Los Angeles  $300  Jan-08-1999 
Boston  $700  Jan-08-1999

Internet Sales 表格   Date  Sales 
Jan-07-1999  $250 
Jan-10-1999  $535 
Jan-11-1999  $320 
Jan-12-1999  $750
而我们要找出有店面营业额以及网络营业额的日子。要达到这个目的,我们用以下的SQL语句:
SELECT Date FROM Store_Information
UNION ALL
SELECT Date FROM Internet_Sales 结果:  
Date 
Jan-05-1999 
Jan-07-1999 
Jan-08-1999 
Jan-08-1999 
Jan-07-1999 
Jan-10-1999 
Jan-11-1999 
Jan-12-1999

============

表1
A   B
a   1
b   0
c   3
d   0
e   2
表2
A   B
c   0
e   4
合并两个表除去重复的数据(以表2的数据为主),我们将会得到以下的表:
A   B
a   1
b   0
c   0
d   0
e   4

select A,B from 表1 where A not in(select A from 表2)
union
select A,B from 表2

巧用一条SQL 实现其它进制到十进制转换

发布时间:2007.09.25 04:57     来源:赛迪网    作者:han
问:怎样实现ORACLE中用一条SQL实现其它进制到十进制的转换?
答:具体示例如下:
-----二进制转换十进制-----------------
select sum(data1)
  from (select substr('1101', rownum, 1) * power
(2, length('1101') - rownum) data1
          from dual
        connect by rownum <= length('1101'))

-----八进制转换十进制-----------------
select sum(data1)
  from (select substr('1101', rownum, 1) * power
(8, length('1101') - rownum) data1
          from dual
        connect by rownum <= length('1101'))

-----十六进制转换十进制-----------------
select sum(data1)
  from (select (CASE upper(substr('2D', rownum, 1))
WHEN 'A' THEN '10'
WHEN 'B' THEN '11'
WHEN 'C' THEN '12'
WHEN 'D' THEN '13'
WHEN 'E' THEN '14'
WHEN 'F' THEN '15'
ELSE substr('2D', rownum, 1)
END) * power(16, length('2D') - rownum) data1
from dual
connect by rownum <= length('2D'))
注释:
对其它进制可以根据例子将power的底数改成相应的进制就可以了。
本文只是一个例子,大家可以把它封装成一个通用函数进行实用。
大家在试的时候将里面相应的其它进制的数值换成自己的数据就可以了(有多处)。
实例讲解如何才能让你的SQL运行得更快 (1)

发布时间:2008.01.22 04:52     来源:赛迪网    作者:10633
很多人在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。
笔者在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。
在对它们进行适当的优化后,其运行速度有了明显地提高!
下面我将从这三个方面分别进行总结:
为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均表示为(< 1秒)。----
测试环境: 主机:HP LH II---- 主频:330MHZ---- 内存:128兆----
操作系统:Operserver5.0.4----
数据库:Sybase11.0.3
一、不合理的索引设计
例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况:
1.在date上建有一非个群集索引
select count(*) from record where date >
'19991201' and date < '19991214'and amount >2000 (25秒)
select date ,sum(amount) from record group by date(55秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH') (27秒)
分析:date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。
2.在date上的一个群集索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >2000 (14秒)
select date,sum(amount) from record group by date(28秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(14秒)
分析:在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。
3.在place,date,amount上的组合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >2000 (26秒)
select date,sum(amount) from record group by date(27秒)
select count(*) from record where date >
'19990901' and place in ('BJ, 'SH')(< 1秒)
分析:这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组合索引中,形成了索引覆盖,所以它的速度是非常快的。
4.在date,place,amount上的组合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >2000(< 1秒)
select date,sum(amount) from record group by date(11秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(< 1秒)
分析:这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。
5.总结:
缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上。
一般来说:
①.有大量重复值、且经常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,可考虑建立群集索引;
②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;
③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。
二、不充份的连接条件:
例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:
select sum(a.amount) from account a,
card b where a.card_no = b.card_no(20秒)
select sum(a.amount) from account a,
card b where a.card_no = b.card_no and
a.account_no=b.account_no(< 1秒)
分析:>在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:
外层表account上的22541页+(外层表account的191122行*内层表card上对应外层表第一行所要查找的3页)=595907次I/O
在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一行所要查找的4页)= 33528次I/O
可见,只有充份的连接条件,真正的最佳方案才会被执行。
总结:
1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案。
2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)。
三、不可优化的where子句
1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
select * from record wheresubstring(card_no,1,4)='5378'(13秒)
select * from record whereamount/30< 1000(11秒)
select * from record whereconvert(char(10),date,112)='19991201'(10秒)
分析:
where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;
如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
select * from record where card_no like'5378%'(< 1秒)
select * from record where amount< 1000*30(< 1秒)
select * from record where date= '1999/12/01'(< 1秒)
你会发现SQL明显快起来!
2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
select count(*) from stuff where id_no in('0','1')(23秒)
分析:---- where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1')转化为id_no ='0' or id_no='1'来执行。
我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;
但实际上(根据showplan),它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。
实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时间竟达到220秒!还不如将or子句分开:
select count(*) from stuff where id_no='0'
select count(*) from stuff where id_no='1'
得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有3秒,在620000行下,时间也只有4秒。
或者,用更好的方法,写一个简单的存储过程:
create proc count_stuff asdeclare @a intdeclare
@b intdeclare @c intdeclare @d char(10)beginselect
@a=count(*) from stuff where id_no='0'select
@b=count(*) from stuff where id_no='1'endselect
@c=@a+@bselect @d=convert(char(10),@c)print @d
直接算出结果,执行时间同上面一样快!
总结:
大家可以看到,优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。
1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。
2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。
3.要善于使用存储过程,它使SQL变得更加灵活和高效。
从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。



利用"SQL"语句自动生成序号的两种方式

发布时间:2008.03.13 04:55     来源:赛迪网    作者:Alizze
【赛迪网-IT技术报道】SQL Server2005数据库中利用SQL语句自动生成序号:
1.首先,我们来介绍第一种方式:
◆查询的SQL语句如下:
select row_number() over (order by name) as rowid, sysobjects.[name] from sysobjects
◆运行的结果:
rowid   name
1           all_columns
2           all_objects
3           all_parameters
4           all_sql_modules
5           all_views
2.最后,我们来介绍第二种方式:
在我们利用这种方式生成自动序号时,Test_Table必须在数据库中不能存在,因为在执行这些SQL语句的时后自动会创建表。
select id=IDENTITY(int,1,1), sysobjects.[name] as name into dbo.Test_Table from sysobjects



详细讲解有关获取当月天数的实用技巧

发布时间:2008.01.24 04:39     来源:赛迪网    作者:陈莫
获取当月天数的实用技巧:
以下是引用片段:
select day(dateadd(mm,1,getdate())-day(getdate()))
--获得当月天数
分析如下:
select getdate()  --当前日期

select day(getdate()) --目前第几天

select getdate()-day(getdate())   --上个月最后一天

select dateadd(mm,1,getdate())-day(getdate())  --加上一个月

select day(dateadd(mm,1,getdate())-day(getdate())) --获得当月天数
  
以下是引用片段:
<script language="VBScript">
Dim dt1, dt2
dt1 = Date
dt1 = CDate(Year(dt1) & "-" & Month(dt1) & "-1") ' 得到本月第一天
dt2 = DateAdd("m", 1, dt1) ' 得到上个月第一天
MsgBox DateDiff("d", dt1, dt2) ' 得到两个月的差
</script>
以下是引用片段:
<script language="jscript">
var dt = new Date(); //得到当前时间
dt = new Date(dt.getFullYear(), dt.getMonth() + 1, 0); //得到本月最后一天
alert(dt.getDate()); // 本月最后一天即为本月的天数
</script>



取一表前N条记录 各个数据库的不同SQL写法
从别处看到的,本人在用的是DB2,竟然都不一样……看来是不能说“会SQL,所有的数据库用起来都一样”了。

1. ORACLE 
SELECT * FROM TABLE1 WHERE ROWNUM<=N 
2. INFORMIX 
SELECT FIRST N * FROM TABLE1 
3. DB2 
SELECT * ROW_NUMBER() OVER(ORDER BY COL1 DESC) AS ROWNUM WHERE ROWNUM<=N 
DB2 
SELECT COLUMN FROM TABLE FETCH FIRST N ROWS ONLY 
4. SQL SERVER 
SELECT TOP N * FROM TABLE1 
5. SYBASE 
SELECT TOP N * FROM TABLE1 
6. mysql: 
select * from table_name limit N

为什么SQL不许在视图定义ORDER BY子句

发布时间:2007.08.03 05:01     来源:赛迪网    作者:luoyingshu
问:为什么SQL Server不允许在视图定义使用ORDER BY子句?
答: SQL Server之所以不允许在视图定义中使用ORDER BY子句是为了遵守ANSI SQL-92标准。因为对该标准的原理分析需要对结构化查询语言(SQL)的底层结构和它所基于的数学理论进行讨论,我们不能在这里对它进行充分的解释。但是,如果你需要在视图中指定ORDER BY子句,可以考虑使用以下方法:
USE pubs
GO

CREATE VIEW AuthorsByName
AS
SELECT TOP 100 PERCENT *
FROM authors
ORDER BY au_lname, au_fname
GO
Microsoft在SQL Server 7.0中引入的TOP结构在同ORDER BY子句结合使用时是非常有用的。只有在同TOP关键词结合使用时,SQL Server才支持在视图中使用ORDER BY子句。
注意:TOP关键词是SQL Server对ANSI SQL-92标准的扩展。
一条SQL语句变得巨慢的原因及其解决方法

发布时间:2008.01.30 04:58     来源:赛迪网    作者:赵震
现象:一条SQL突然运行的特别慢。
select uidTable.column_value, first_name||' '
||last_name, company, job_title, upper(member_level),
upper(service_value)
from (select * from table(select cast(multiset
(select b from bbb)as Taaa) from dual)) uidTable,member
where uidTable.column_value = member.login_id(+)
and member.site='alibaba' and member.site='test';
出错原因:用户增加了一个条件member.site=test,造成连接的顺序变化了,原来的驱动表是uidTable(最多1024条记录),现在变成了member表做驱动(600W条)。所以这条语句变的巨慢。
但是既然是外连接,为什么连接的顺序会改变呢?因为外连接的连接顺序不是由COST决定的,而是由连接的条件决定的。发现执行计划如下:
-------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------
| 0 | SELECT STATEMENT | | 1018 | 72278 | 8155 |
| 1 | NESTED LOOPS | | 1018 | 72278 | 8155 |
| 2 | VIEW | | 4072 | 69224 | 11 |
| 3 | COLLECTION ITERATOR SUBQUERY FETCH| | | | |
| 4 | TABLE ACCESS FULL | DUAL | 4072 | | 11 |
| 5 | TABLE ACCESS FULL | BBB | 41 | 287 | 2 |
| 6 | TABLE ACCESS BY INDEX ROWID | MEMBER | 1 | 54 | 2 |
|* 7 | INDEX UNIQUE SCAN | MEMBER_SITE_LID_PK | 4 | | 1 |
-------------------------------------------------
为什么根本就没有执行外连接呢?问题出在member.site='test'这个条件上,因为对外连接的表加了条件,造成外连接失效。改为member.site(+)='test'后,问题彻底解决。
---------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-----------------------------------------------------
| 0 | SELECT STATEMENT | | 1018 | 72278 | 8155 |
| 1 | NESTED LOOPS | | 1018 | 72278 | 8155 |
| 2 | VIEW | | 4072 | 69224 | 11 |
| 3 | COLLECTION ITERATOR SUBQUERY FETCH| | | | |
| 4 | TABLE ACCESS FULL | DUAL | 4072 | | 11 |
| 5 | TABLE ACCESS FULL | BBB | 41 | 287 | 2 |
| 6 | TABLE ACCESS BY INDEX ROWID | MEMBER | 1 | 54 | 2 |
|* 7 | INDEX UNIQUE SCAN | MEMBER_SITE_LID_PK | 4 | | 1 |
-----------------------------------------------------------



教你快速掌握SQL语句各种写法的效率问题

发布时间:2008.04.22 08:49     来源:赛迪网    作者:科林
【赛迪网-IT技术报道】问题1:一次插入多条数据时下面这两种方法,哪种方法效率高?
CREATE TABLE tb(ID int, 名称 NVARCHAR(30), 备注 NVARCHAR(1000))
INSERT tb SELECT 1,'DDD',1
UNION ALL SELECT 1,'5100','D'
UNION ALL SELECT 1,'5200','E'
也可以这样写:
CREATE TABLE tb1(ID int, 名称 NVARCHAR(30), 备注 NVARCHAR(1000))
INSERT TB1 (ID,名称,备注)VALUES(1,'DDD',1)
INSERT TB1 (ID,名称,备注)VALUES(1,'5100','D')
INSERT TB1 (ID,名称,备注)VALUES(1,'5200','E')
解答:
第1种好一些, 但也得有个量的控制, 因为第1种的union all是作为一个语句整体, 查询优化器会尝试做优化, 同时, 也要先算出这个结果再插入的。
问题2:
赋值时:
SELECT @a=N'aa'
SET @a=N'aa'
上面两种方法,哪种方法效率高?
解答:
如果是单个赋值, 没有什么好比较的话.
不过, 如果是为多个变量赋值, 经测试, SELECT 一次性赋值, 比用SET 逐个赋值效率好..
问题3:取前几条数据时
set ROWCOUNT 2 select * from tb order by fd
select Top 2 * from tb order by fd
上面两种方法,哪种方法效率高?
答:
SET ROWCOUNT和TOP 是一样的, 包括执行的计划等都是一样的
问题4:条件判断时:
where 0<(select count(*) from tb where ……)
where exists(select * from tb where ……)
上面两种方法,哪种方法效率高?
答:
这个一般是exists快, 当然, 具体还要看你后面的子查询的条件, 是否会引用外层查询中的对象的列.
exists检查到有值就返回, 而且不返回结果集, count需要统计出所有满足条件的, 再返回一个结果集, 所以一般情况下exists快.
问题5:
(5)NULLIF的使用----->同理它的反函数ISNULL的使用
update tb set fd=case when fd=1 then null else fd end
update tb set fd=nullif(fd,1)
上面两种方法,哪种方法效率高?
答:
应该是一样的
问题6:从字符串中取子字符串时
substring('abcdefg',1,3)
left('abcderg',3)_
上面两种方法,哪种方法效率高?
答:
基本上是一样的
问题7:EXCEPT和Not in的区别?
答:
except会去重复, not in 不会(除非你在select中显式指定)
except用于比较的列是所有列, 除非写子查询限制列, not in 没有这种情况
问题8:INTERSECT和UNION的区别?
答:intersect是两个查询都有的非重复值(交集), union是两个查询结果的所有不重复值(并集)

通过两个例子讲解PIVOT/UNPIVOT的用法

发布时间:2008.03.13 04:58     来源:赛迪网    作者:ChenJaYi
【赛迪网-IT技术报道】使用过SQL Server 2000的人都知道,要想实现行列转换,必须综合利用聚合函数和动态SQL,具体实现起来需要一定的技巧,而在SQL Server 2005中,使用新引进的关键字PIVOT/UNPIVOT,则可以很容易的实现行列转换的需求。
在本文中我们将通过两个简单的例子详细讲解PIVOT/UNPIVOT的用法。
PIVOT的用法:
首先创建测试表,然后插入测试数据
create table test(id int,name varchar(20),quarter int,profile int)
insert into test values(1,'a',1,1000)
insert into test values(1,'a',2,2000)
insert into test values(1,'a',3,4000)
insert into test values(1,'a',4,5000)
insert into test values(2,'b',1,3000)
insert into test values(2,'b',2,3500)
insert into test values(2,'b',3,4200)
insert into test values(2,'b',4,5500)

select * from test
id name quarter profile
----------- -------------- ----------- -----------
1 a 1 1000
1 a 2 2000
1 a 3 4000
1 a 4 5000
2 b 1 3000
2 b 2 3500
2 b 3 4200
2 b 4 5500

(8 row(s) affected)

使用PIVOT将四个季度的利润转换成横向显示:

select id,name,
[1] as "一季度",
[2] as "二季度",
[3] as "三季度",
[4] as "四季度"
from
test
pivot
(
sum(profile)
for quarter in
([1],[2],[3],[4])
)
as pvt

id name 一季度 二季度 三季度 四季度
-------- --------- ----------- -------- ------- -------
1 a 1000 2000 4000 5000
2 b 3000 3500 4200 5500

(2 row(s) affected)
UNPIVOT的用法:
首先建立测试表,然后插入测试数据

drop table test

create table test(id int,name varchar(20), Q1 int, Q2 int, Q3 int, Q4 int)

insert into test values(1,'a',1000,2000,4000,5000)
insert into test values(2,'b',3000,3500,4200,5500)


select * from test

id name Q1 Q2 Q3 Q4
-------- ------- --------- --------- -------- --------
1 a 1000 2000 4000 5000
2 b 3000 3500 4200 5500

(2 row(s) affected)

使用UNPIVOT,将同一行中四个季度的列数据转换成四行数据:

select id,name,quarter,profile
from
test
unpivot
(
profile
for quarter in
([Q1],[Q2],[Q3],[Q4])
)
as unpvt

id name quarter profile
----------- ----------- ---------- -----------
1 a Q1 1000
1 a Q2 2000
1 a Q3 4000
1 a Q4 5000
2 b Q1 3000
2 b Q2 3500
2 b Q3 4200
2 b Q4 5500

(8 row(s) affected)


用一个实例讲解GROUP BY CEIL的使用方法

发布时间:2008.01.31 05:07     来源:赛迪网    作者:孙诗涵
GROUP BY CEIL的使用方法:
SQL> WITH A AS (SELECT 'A' CD FROM DUAL
2 UNION
3 SELECT 'B' CD FROM DUAL
4 UNION
5 SELECT 'C' CD FROM DUAL
6 UNION
7 SELECT 'D' CD FROM DUAL
8 UNION
9 SELECT 'E' CD FROM DUAL
10 UNION
11 SELECT 'F' CD FROM DUAL
12 UNION
13 SELECT 'G' CD FROM DUAL
14 UNION
15 SELECT 'H' CD FROM DUAL
16 UNION
17 SELECT 'I' CD FROM DUAL
18 )
19 select max(decode(mod(rownum, 5), 1, CD, null)) ID1,
20 max(decode(mod(rownum, 5), 2, CD, null)) ID2,
21 max(decode(mod(rownum, 5), 3, CD, null)) ID3,
22 max(decode(mod(rownum, 5), 4, CD, null)) ID4,
23 max(decode(mod(rownum, 5), 0, CD, null)) ID5
24 from a
25 group by ceil(rownum / 5)
26 ;

ID1 ID2 ID3 ID4 ID5
--- --- --- --- ---
A B C D E
F G H I


例二:

with a as (select '01' ym from dual
union
select '02' ym from dual
union
select '03' ym from dual
union
select '04' ym from dual
union
select '05' ym from dual
union
select '06' ym from dual
union
select '07' ym from dual
union
select '08' ym fr
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics