SQL代碼優化

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章