SQL代码优化

来源:互联网 发布:淘宝大卖家发货单打印 编辑:程序博客网 时间:2024/05/18 00:14

EXEC和sp_executesql的区别?


DBCC FREEPROCCACHE --》清空缓存中的执行计划
SELECT cacheobjtype,objtype,usecounts,sql FROM sys.syscacheobjects WHERE sql NOT LIKE '%cach%' AND sql NOT LIKE '%sys.%' --》查找对应的缓存中的对应计划


SQL Server为每一个的查询字符串创建新的执行计划,即使查询模式相同也是这样
EXEC除了不支持动态批处理中的输入参数外,他也不支持输出参数
用法:
Exec('select * from CustInfo')
Exec sp_executesql N'select * from CustInfo'

declare @paraName varchar(20)
set @paraName='CustName'
Exec('select '+@paraName+' from CustInfo')--加号前后加上空格


如果你要把输出返回给调用批处理中的变量:

DECLARE @sql NVARCHAR(MAX),@RecordCount INT

SET @sql = 'SELECT COUNT(ORDERID) FROM Orders';

CREATE TABLE #T(TID INT);

INSERT INTO #T EXEC(@sql);

SET @RecordCount = (SELECT TID FROM #T)

SELECT @RecordCount

DROP TABLE #T


sp_executesql命令在SQL Server中引入的比EXEC命令晚一些,它主要为重用执行计划提供更好的支持。
它的构成包括:代码快,参数声明部分,参数赋值部分
EXEC sp_executesql

@stmt = <statement>,--类似存储过程主体

@params = <params>, --类似存储过程参数部分

<params assignment> --类似存储过程调用


@stmt参数是输入的动态批处理,它可以引入输入参数或输出参数,和存储过程的主体语句一样,只不过它是动态的,而存储过程是静态的,不过你也可以在存储过程中使用sp_executesql;

@params参数与定义输入/输出参数的存储过程头类似,实际上和存储过程头的语法完全一样;

@<params assignment> 与调用存储过程的EXEC部分类似。

用法:

declare @paraName varchar(20)
set @paraName='CustName'
declare @temp nvarchar(1000)
set @temp='select ' +@paraName+ ' from CustInfo'
Exec(@temp)
exec sp_executesql  @temp--因为 sp_executesql只能执行的类型为ntext/nchar/nvarchar,所以@temp需要从varchar改为nvarchar

  DECLARE @TableName VARCHAR(50),@sql NVARCHAR(MAX),@OrderID INT;

      SET @TableName = 'CustInfo ';

      SET @OrderID = 10;

     SET @sql = 'SELECT * FROM '+QUOTENAME(@TableName) + ' WHERE  ID = @OID ORDER BY ORDERID DESC'

      EXEC sp_executesql

          @stmt = @sql,

          @params = N'@OID AS INT ',

          @OID = @OrderID


QUOTENAME的用法?
当你的生成的表名为aa[]bb,执行如下
exec('select * from aa[]bb') --》肯定会出错
则必须写为
set @sql='select * from ' + quotename('aa[]bb')
exec(@sql)
quotename 使函数中的输入成为一个有效的标识符。
比如上例中 aa[]bb 不是一个有效的标识符。

quotename函数有几种写法:
  quotename('aa') 生成的有效的标识符为 [aa]
  quotename('aa','') 生成的有效的标识符为 [aa]
  quotename('aa','''') 生成的有效的标识符为 'aa'---》''''为四个单引号


CHECKIDENT的用法?
当表中的记录被全部删除,但此时标识列的值越来越大的时候,如果不加以重置,它还会无休止的增长。
DBCC CHECKIDENT(TABLE, [RESEED|NORESEED], [1])
将把指定表的种子值强制重设为1。
然而,你可能不想将种子重设为1,
在这种情况下,你可以用你想用的种子值替代第三个参数。
有时候你可能想知道当前的种子,而不是想重设种子,这时你就要用到NORESEED,而不用再去顾忌第三个参数。
应用如下:
DBCC CHECKIDENT('RoomReservation',NORESEED)
DBCC CHECKIDENT('RoomReservation',RESEED,1)--》当然如果在有数据的时候重定义种子,则产生的列值将不唯一,有重复的可能


某列为自动增长列,如何插入一个固定的值呢?
  SET   IDENTITY_INSERT   RoomReservation   ON 
  insert   RoomReservation   (Id,RoomName)   values   ('20','111')   
  SET   IDENTITY_INSERT   RoomReservation   OFF  
而此时的种子也将更改值为20


删除重复行
SELECT语句中使用ALL或DISTINCT选项来显示表中符合条件的所有行或删除其中重复的数据行,默认为ALL。
使用DISTINCT选项时,对于所有重复的数据行在SELECT返回的结果集合中只保留一行。
例子:
Delete   DISTINCT   *   FROM   Table   Where   字段1=条件1   And   字段2=条件2

如何限制返回的行数 ?

SELECT   TOP   20   PERCENT   *   FROM   RoomReservation--》将返回数据条数的20%数据
SELECT   TOP   20   PERCENT   *   FROM   RoomReservation--》返回前20条数据


怎样改变Union的执行顺序?
1 UNION (查询2 UNION 查询3)

连接查询
FROM   join_table   join_type   join_table
[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)


内连接时,返回查询结果集合中的仅是符合查询条件( WHERE 搜索条件或 HAVING 条件)和连接条件的行。
这里将不以哪个表为基准,而匹配的才显示。而外连接是以某个表为基准,如果另外一个表没有的时候,就填充NULL

用外连接时,它返回到查询结果集合中的不仅包含符合连接条件的行,而且还包括左表(左外连接时)、右表(右外连接时)或两个边接表(全外连接)中的所有数据行。


交叉连接不带WHERE 子句,它返回被连接的两个表所有数据行的笛卡尔积,返回到结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。
在使用CROSS JOIN关键字交叉连接表时,因为生成的是两个表的笛卡尔积,因而不能使用ON关键字,只能在WHERE子句中定义搜索条件。


 JOIN 语句中链接多个 ON 子句,请使用如下语法:

SELECT fields
FROM table1 INNER JOIN table2
ON table1.field1 compopr table2.field1 AND
ON table1.field2 compopr table2.field2) OR
ON table1.field3 compopr table2.field3)];

也可以通过如下语法嵌套 JOIN 语句:

SELECT fields
FROM table1 INNER JOIN
(table2 INNER JOIN [( ]table3
[INNER JOIN [( ]tablex [INNER JOIN ...)]
ON table3.field3 compopr tablex.fieldx)]
ON table2.field2 compopr table3.field3)
ON table1.field1 compopr table2.field2;

LEFT JOIN 或 RIGHT JOIN 可以嵌套在 INNER JOIN 之中,但是 INNER JOIN 不能嵌套于 LEFT JOIN 或 RIGHT JOIN 之中。


DateDiff函数的用法?
DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]])
interval:
year   |   quarter   |   month   |   week   |   day   |   hour   |   minute   |   second   |   millisecond  

firstdayofweek(每个星期的第一天) :
 vbUseSystem 0 使用 NLS API 设置。
  vbSunday 1 星期日(缺省值)
  vbMonday 2 星期一
  vbTuesday 3 星期二
  vbWednesday 4 星期三
  vbThursday 5 星期四
  vbFriday 6 星期五
  vbSaturday 7 星期六
firstweekofyear(每年的第一天):
 vbUseSystem 0 用 NLS API 设置。
  vbFirstJan1 1 从包含 1 月 1 日的星期开始(缺省值)。
  vbFirstFourDays 2 从第一个其大半个星期在新的一年的一周开始。
  vbFirstFullWeek 3 从第一个无跨年度的星期开始。

当 interval 是“一周的日数”(w) 时,DateDiff 返回两日期间的周数。
如果 date1 是星期一,DateDiff 计算到 date2 为止的星期一的个数。
这个数包含 date2 但不包含 date1。
不过,如果 interval 是“周”(ww),则 DateDiff 函数返回两日期间的“日历周”数。
由计算 date1 与 date2 之间星期日的个数而得。
如果 date2 刚好是星期日,则 date2 也会被加进 DateDiff 的计数结果中;
但不论 date1 是否为星期日,都不将它算进去。

如果 date1 比 date2 来得晚,则 DateDiff 函数的返回值为负数。date2-data1<0
如果 date1 比 date2 来得早,则 DateDiff 函数的返回值为正数。date2-data1>0

如果 date1 或 date2 是日期文字,则指定的年份成为该日期的固定部分。
如果 date1 或 date2 用双引号 (" ") 括起来,且年份略而不提,则在每次计算表达式 date1 或 date2 时,当前年份都会插入到代码之中。
这样就可以书写适用于不同年份的程序代码。

ACCESS中用法:DATEDIFF('day', pubdate, Now())
MSSQL中用法:DATEDIFF(day, pubdate, getdate())
例子:
查找提前据现在时间提前五分钟的日程安排
select * from 日程安排 where datediff('minute',f开始时间,getdate())>5

SQL分页
SELECT TOP 页大小 *
FROM table1
WHERE id NOT IN
          (
          SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id
          )
ORDER BY id

方法2:
适用于 SQL Server 2000/2005
SELECT TOP 页大小 *
FROM table1
WHERE id >
          (
          SELECT ISNULL(MAX(id),0)
          FROM
                (
                SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id
                ) A
          )
ORDER BY id

方法3:
适用于 SQL Server 2005
SELECT TOP 页大小 *
FROM
        (
        SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1
        ) A
WHERE RowNumber > 页大小*(页数-1)

方法4:
在查询100页以下四种方法的效率差不多,但在1000页以后就大大折扣,唯有第四种方法效率很高
-- 获取指定页的数据

CREATE PROCEDURE pagination3

@tblName varchar(255), -- 表名

@strGetFields varchar(1000) = '*', -- 需要返回的列

@fldName varchar(255)='', -- 排序的字段名

@PageSize int = 10, -- 页尺寸

@PageIndex int = 1, -- 页码

@doCount bit = 0, -- 返回记录总数, 非 0 值则返回

@OrderType bit = 0, -- 设置排序类型, 非 0 值则降序

@strWhere varchar(1500) = '' -- 查询条件 (注意: 不要加 where)

AS

declare @strSQL varchar(5000) -- 主语句

declare @strTmp varchar(110) -- 临时变量

declare @strOrder varchar(400) -- 排序类型



if @doCount != 0

begin

if @strWhere !=''

set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere

else

set @strSQL = "select count(*) as Total from [" + @tblName + "]"

end

--以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况

else

begin



if @OrderType != 0

begin

set @strTmp = "<(select min"

set @strOrder = " order by [" + @fldName +"] desc"

--如果@OrderType不是0,就执行降序,这句很重要!

end

else

begin

set @strTmp = ">(select max"

set @strOrder = " order by [" + @fldName +"] asc"

end



if @PageIndex = 1

begin

if @strWhere != ''

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from [" + @tblName + "] where " + @strWhere + " " + @strOrder

else

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["+ @tblName + "] "+ @strOrder

--如果是第一页就执行以上代码,这样会加快执行速度

end

else

begin

--以下代码赋予了@strSQL以真正执行的SQL代码

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["

+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName

+ "]" + @strOrder + ") as tblTmp)"+ @strOrder



if @strWhere != ''

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ " from ["

+ @tblName + "] where [" + @fldName + "]" + @strTmp + "(["

+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["

+ @fldName + "] from [" + @tblName + "] where " + @strWhere + " "

+ @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder

end

end

exec (@strSQL)

GO



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;

(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;


嵌套子查询中的活用IN将很好的用处


SQL Union和Union All的使用方法?
UNION的一个限制是两个 SQL 语句所产生的栏位需要是同样的资料种类。
另外,当我们用 UNION这个指令时,我们只会看到不同的资料值 (类似 SELECT DISTINCT)。而UNION ALL 会将每一笔符合条件的资料都列出来,无论资料值有无重复
 union只是将两个结果联结起来一起显示,并不是联结两个表
例子:
SELECT Date FROM Store_Information
UNION
SELECT Date FROM Internet_Sales
,如果我们在任何一个 SQL 语句 (或是两句都一起) 用 "SELECT DISTINCT Date" 的话,那我们会得到完全一样的结果。
 

聚焦索引和非聚焦索引

内容本身就是一种按照一定规则排列的目录称为“聚集索引“;既不能绝大多数都相同,又不能只有极少数相同
聚集索引的最大好处就是能够根据查询要求,迅速缩小查询范围,避免全表扫描;

非聚集索引 等于我们查找汉语字典的某一个,只能根据偏旁部首来查询

何时使用聚集索引或非聚集索引(很重要)。
动作描述        列经常被分组排序   返回某范围内的数据  一个或极少不同值  小数目的不同值  大数目的不同值  频繁更新的列  外键列  主键列  频繁修改索引列
使用聚集索引          应               应                    不应              应          不应             应          应       应        不应
使用非聚集索引        应               不应                  不应              不应          应             不应        应       应         应

注意:不要将聚集索引盲目地建在ID这个主键上
(1)仅在主键上建立聚集索引,并且不划分时间段:

Select gid,fariqi,neibuyonghu,title from tgongwen

用时:128470毫秒(即:128秒)

(2)在主键上建立聚集索引,在fariq上建立非聚集索引:

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

用时:53763毫秒(54秒)

(3)将聚合索引建立在日期列(fariqi)上:

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

用时:2423毫秒(2秒)

并非是在任何字段上简单地建立索引就能提高查询速度

用复合聚集索引的非起始列作为查询条件的话,这个索引是不起任何作用的
无论您是否经常使用聚合索引的其他列,但其前导列一定要是使用最频繁的列。


1、用聚合索引比用不是聚合索引的主键速度快
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'

使用时间:3326毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000

使用时间:4470毫秒

这里,用聚合索引比用不是聚合索引的主键速度快了近1/4。

2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下
select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi

用时:12936

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid

用时:18843

这里,用聚合索引比用一般的主键作order by时,速度快了3/10。事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如

10万以上,则二者的速度差别不明显。

3 、日期列不会因为有分秒的输入而减慢查询速度
4.但过多或不当的索引也会导致系统低效。因为用户在表中每加进一个索引,数据库就要做更多的工作。过多的索引甚至会导致索引碎片。



怎样优化你的SQL?
select * from table1 where name='zhangsan' and tID > 10000
select * from table1 where tID > 10000 and name='zhangsan' 执行效率是否一样?

事实上,这样的担心是不必要的。
SQL SERVER中有一个“查询分析优化器”,它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化
在查询分析阶段,查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数(SARG),那么就称之为可优化的,并且可以利用索引快速

获得所需数据。
列名 操作符 <常数 或 变量>



<常数 或 变量> 操作符列名

如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。
所以一个索引对于不满足SARG形式的表达式来说是无用的
1、Like语句是否属于SARG取决于所使用的通配符的类型

如:name like ‘张%’ ,这就属于SARG

而:name like ‘%张’ ,就不属于SARG。

YY_BH LIKE ‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’

原因是通配符%在字符串的开通使得索引无法使用。
2、or 会引起全表扫描 不符合SARG
3、非操作符、函数引起的不满足SARG形式的语句
满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等,另外还有函数。
有些表达式,如:

WHERE 价格*2>5000

SQL SERVER也会认为是SARG,SQL SERVER会将此式转化为:

WHERE 价格>2500/2
<> 操作符(不等于)
用其它相同功能的操作运算代替,如
a<>0 改为 a>0 or a<0

a<>’’ 改为 a>’’

IS NULL 或IS NOT NULL操作(判断字段是否为空)
a is not null 改为 a>0 或a>’’

4、IN 的作用相当与OR

语句:

Select * from table1 where tid in (2,3)



Select * from table1 where tid=2 or tid=3

是一样的,都会引起全表扫描,如果tid上有索引,其索引也会失效。
5、尽量少用NOT
6、exists 和 in 的执行效率是一样的

7、用函数charindex()和前面加通配符%的LIKE执行效率一样
8、union并不绝对比or的执行效率高
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or gid>9990000

用时:68秒。扫描计数 1,逻辑读 404008 次,物理读 283 次,预读 392163 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000

用时:9秒。扫描计数 8,逻辑读 67489 次,物理读 216 次,预读 7499 次。

看来,用union在通常情况下比用or的效率要高的多。

发现如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or fariqi='2004-2-5'

用时:6423毫秒。扫描计数 2,逻辑读 14726 次,物理读 1 次,预读 7176 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-2-5'

用时:11640毫秒。扫描计数 8,逻辑读 14806 次,物理读 108 次,预读 1144 次。

9、字段提取要按照“需多少、提多少”的原则,避免“select *”
select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

用时:4673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc

用时:1376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc

用时:80毫秒

由此看来,我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。

10、count(*)不比count(字段)慢
count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总的速度就越慢。
如果用count(*), SQL SERVER可能会自动查找最小字段来汇总的。当然,如果您直接写count(主键)将会来的更直接些。

11、order by按聚集索引列排序效率最高

12、高效的TOP
实上,在查询和提取超大容量的数据集时,影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作。如:

select top 10 * from (

select top 10000 gid,fariqi,title from tgongwen

where neibuyonghu='办公室'

order by gid desc) as a

order by gid asc

这条语句,从理论上讲,整条语句的执行时间应该比子句的执行时间长,但事实相反。
因为,子句执行后返回的是10000条记录,而整条语句仅返回10条语句,所以影响数据库响应时间最大的因素是物理I/O操作。
而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。
TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用,发现TOP确实很好用,效率也很高。
SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接


户在进行大数据量查询的时候,对数据库速度影响最大的不是内存大小,而是CPU


怎么获得当月的天数?
 
select day(dateadd(mm,1,getdate())-day(getdate()))

怎么样在SQL Server视图中定义使用ORDER BY子句?
CREATE VIEW AuthorsByName
AS
SELECT TOP 100 PERCENT *
FROM authors
ORDER BY au_lname, au_fname
GO
有在同TOP关键词结合使用时,SQL Server才支持在视图中使用ORDER BY子句。
注意:TOP关键词是SQL Server对ANSI SQL-92标准的扩展。

哪种多条插入数据属于效率更高?
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')
也可以写为:
INSERT INTO tbl_name (col1, col2)
VALUES (value1_1, value1_2),
(value2_1, value2_2),(value3_1, value3_2)
当某一个有错的时候,后面的数据也不会插入


第一个的效率要远远高于第二条,而此时的UNION ALL 比UNION 的效率高很多的,而是用UNION如果表数据量大的话可能会导致用磁盘进行排序,而UNION ALL操作只是简单的将两个结果合并

后就返回。

SELECT 和Set为变量赋值哪个效率高些?
 SELECT 一次性赋值, 比用SET 逐个赋值效率好..

EXCEPT 和 INTERSECT关键字的用法
 SELECT * FROM TableA EXCEPT SELECT * FROM TableB;--> 以TableA为基表和TableB对比,返回TableA和TableB中具有不重复数据的记录
SELECT * FROM TableA INTERSECT SELECT * FROM TableB;-->以TableA和TableB为基表,返回TableA和TableB中具有重复数据的记录

怎么样根据数据产生动态的列
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 id,name,
[1] as "一季度",
[2] as "二季度",
[3] as "三季度",
[4] as "四季度"
from
test
pivot
(
sum(profile)
for quarter in
([1],[2],[3],[4])
)
as pvt

UNPIVOT的用法:
将同一行中四个季度的列数据转换成四行
select id,name,quarter,profile
from
test
unpivot
(
profile
for quarter in
([Q1],[Q2],[Q3],[Q4])
)
as unpvt


原创粉丝点击