轉載自:http://www.cnblogs.com/knowledgesea/p/3699851.html。
什麼是遊標
結果集,結果集就是select查詢以後返回的全部行數據的集合。html
遊標則是處理結果集的一種機制吧,它能夠定位到結果集中的某一行,多數據進行讀寫,也能夠移動遊標定位到你所須要的行中進行操做數據。sql
通常複雜的存儲過程,都會有遊標的出現,他的用處主要有:數據庫
- 定位到結果集中的某一行。
- 對當前位置的數據進行讀寫。
- 能夠對結果集中的數據單獨操做,而不是整行執行相同的操做。
- 是面向集合的數據庫管理系統和麪向行的程序設計之間的橋樑。
遊標的分類
根據遊標檢測結果集變化的能力和消耗資源的狀況不一樣,SQL Server支持的API服務器遊標分爲一下4種:express
- 靜態遊標: 靜態遊標的結果集,在遊標打開的時候創建在TempDB中,不論你在操做遊標的時候,如何操做數據庫,遊標中的數據集都不會變。例如你在遊標打開的時候,對遊標查詢的數據表數據進行增刪改,操做以後,靜態遊標中select的數據依舊顯示的爲沒有操做以前的數據。若是想與操做以後的數據一致,則從新關閉打開遊標便可。
- 動態遊標:這個則與靜態遊標相對,滾動遊標時,動態遊標反應結果集中的全部更改。結果集中的行數據值、順序和成員在每次提取時都會變化。全部用戶作的增刪改語句經過遊標都可見。若是使用API函數或T-SQL Where Current of子句經過遊標進行更新,他們將當即可見。在遊標外部所作的更新直到提交時纔可見。
- 只進遊標:只進遊標不支持滾動,只支持從頭至尾順序提取數據,數據庫執行增刪改,在提取時是可見的,但因爲該遊標只能進不能向後滾動,因此在行提取後對行作增刪改是不可見的。
- 鍵集驅動遊標:打開鍵集驅動遊標時,該有表中的各個成員身份和順序是固定的。打開遊標時,結果集這些行數據被一組惟一標識符標識,被標識的列作刪改時,用戶滾動遊標是可見的,若是沒被標識的列增該,則不可見,好比insert一條數據,是不可見的,若可見,須關閉從新打開遊標。
靜態遊標在滾動時檢測不到表數據變化,但消耗的資源相對不多。動態遊標在滾動時能檢測到全部表數據變化,但消耗的資源卻較多。鍵集驅動遊標則處於他們中間,因此根據需求創建適合本身的遊標,避免資源浪費。編程
遊標的生命週期
遊標的生命週期包含有五個階段:聲明遊標、打開遊標、讀取遊標數據、關閉遊標、釋放遊標。數組
1.聲明遊標,語法性能優化
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
參數說明:服務器
- cursor_name:遊標名稱。
- Local:做用域爲局部,只在定義它的批處理,存儲過程或觸發器中有效。
- Global:做用域爲全局,由鏈接執行的任何存儲過程或批處理中,均可以引用該遊標。
- [Local | Global]:默認爲local。
- Forward_Only:指定遊標智能從第一行滾到最後一行。Fetch Next是惟一支持的提取選項。若是在指定Forward_Only是不指定Static、KeySet、Dynamic關鍵字,默認爲Dynamic遊標。若是Forward_Only和Scroll沒有指定,Static、KeySet、Dynamic遊標默認爲Scroll,Fast_Forward默認爲Forward_Only
- Static:靜態遊標
- KeySet:鍵集遊標
- Dynamic:動態遊標,不支持Absolute提取選項
- Fast_Forward:指定啓用了性能優化的Forward_Only、Read_Only遊標。若是指定啦Scroll或For_Update,就不能指定他啦。
- Read_Only:不能經過遊標對數據進行刪改。
- Scroll_Locks:將行讀入遊標是,鎖定這些行,確保刪除或更新必定會成功。若是指定啦Fast_Forward或Static,就不能指定他啦。
- Optimistic:指定若是行自讀入遊標以來已獲得更新,則經過遊標進行的定位更新或定位刪除不成功。當將行讀入遊標時,sqlserver不鎖定行,它改用timestamp列值的比較結果來肯定行讀入遊標後是否發生了修改,若是表不行timestamp列,它改用校驗和值進行肯定。若是已修改改行,則嘗試進行的定位更新或刪除將失敗。若是指定啦Fast_Forward,則不能指定他。
- Type_Warning:指定將遊標從所請求的類型隱式轉換爲另外一種類型時向客戶端發送警告信息。
- For Update[of column_name ,....] :定義遊標中可更新的列。
2.聲明一個動態遊標框架
declare orderNum_02_cursor cursor scroll for select OrderId from bigorder where orderNum='ZEORD003402'
3.打開遊標函數
--打開遊標語法 open [ Global ] cursor_name | cursor_variable_name
cursor_name:遊標名,cursor_variable_name:遊標變量名稱,該變量引用了一個遊標。
--打開遊標 open orderNum_02_cursor
4.提取數據
--提取遊標語法 Fetch [ [Next|prior|Frist|Last|Absoute n|Relative n ] from ] [Global] cursor_name [into @variable_name[,....]]
參數說明:
- Frist:結果集的第一行
- Prior:當前位置的上一行
- Next:當前位置的下一行
- Last:最後一行
- Absoute n:從遊標的第一行開始數,第n行。
- Relative n:從當前位置數,第n行。
- Into @variable_name[,...] : 將提取到的數據存放到變量variable_name中。
例子:
--提取數據 fetch first from orderNum_02_cursor fetch relative 3 from orderNum_02_cursor fetch next from orderNum_02_cursor fetch absolute 4 from orderNum_02_cursor fetch next from orderNum_02_cursor fetch last from orderNum_02_cursor fetch prior from orderNum_02_cursor select * from bigorder where orderNum='ZEORD003402'
結果(對比一下,就明白啦):
例子:
--提取數據賦值給變量 declare @OrderId int fetch absolute 3 from orderNum_02_cursor into @OrderId select @OrderId as id select * from bigorder where orderNum='ZEORD003402'
結果:
經過檢測全局變量@@Fetch_Status的值,得到提取狀態信息,該狀態用於判斷Fetch語句返回數據的有效性。當執行一條Fetch語句以後,@@Fetch_Status可能出現3種值:0,Fetch語句成功。-1:Fetch語句失敗或行不在結果集中。-2:提取的行不存在。
這個狀態值能夠幫你判斷提取數據的成功與否。
declare @OrderId int fetch absolute 3 from orderNum_02_cursor into @OrderId while @@fetch_status=0 --提取成功,進行下一條數據的提取操做 begin select @OrderId as id fetch next from orderNum_02_cursor into @OrderId --移動遊標 end
5.利用遊標更新刪除數據
--遊標修改當前數據語法 Update 基表名 Set 列名=值[,...] Where Current of 遊標名 --遊標刪除當前數據語法 Delete 基表名 Where Current of 遊標名
---遊標更新刪除當前數據 ---1.聲明遊標 declare orderNum_03_cursor cursor scroll for select OrderId ,userId from bigorder where orderNum='ZEORD003402' --2.打開遊標 open orderNum_03_cursor --3.聲明遊標提取數據所要存放的變量 declare @OrderId int ,@userId varchar(15) --4.定位遊標到哪一行 fetch First from orderNum_03_cursor into @OrderId,@userId --into的變量數量必須與遊標查詢結果集的列數相同 while @@fetch_status=0 --提取成功,進行下一條數據的提取操做 begin if @OrderId=122182 begin Update bigorder Set UserId='123' Where Current of orderNum_03_cursor --修改當前行 end if @OrderId=154074 begin Delete bigorder Where Current of orderNum_03_cursor --刪除當前行 end fetch next from orderNum_03_cursor into @OrderId ,@userId --移動遊標 end
6.關閉遊標
遊標打開後,服務器會專門爲遊標分配必定的內存空間存放遊標操做的數據結果集,同時使用遊標也會對某些數據進行封鎖。因此遊標一旦用過,應及時關閉,避免服務器資源浪費。
--關閉遊標語法 close [ Global ] cursor_name | cursor_variable_name --關閉遊標 close orderNum_03_cursor
7.刪除遊標
刪除遊標,釋放資源
--釋放遊標語法 deallocate [ Global ] cursor_name | cursor_variable_name --釋放遊標 deallocate orderNum_03_cursor
C# DataTable.Select() 篩選數據
有時候咱們須要對數據表進行篩選,微軟爲咱們封裝了一個公共方法, DataTable.Select(),其用法以下:
Select()
Select(string filterExpression)
Select(string filterExpression, string sort)
Select(string filterExpression,string sort, DataViewRowState record States)
1) Select()——獲取全部 System.Data.DataRow 對象的數組;
2) Select(string filterExpression)——按照主鍵順序(若是沒有主鍵,則按照添加順序)獲取與篩選條件相匹配的全部 System.Data.DataRow 對象的數組;
3) Select(string filterExpression, string sort)——獲取按照指定的排序順序且與篩選條件相匹配的全部System.Data.DataRow 對象的數組;
4) Select(string filterExpression, string sort, DataViewRowState recordStates)——獲取與排序順序中的篩選器以及指定的狀態相匹配的全部。
舉例說明:
有一個用戶表,名稱爲 dtUsers,有id、姓名name、性別sex、年齡age
1.篩選全部的用戶
DataRow[] drs1 =dtUsers.Select();
2.篩選全部性別爲男的用戶
DataRow[] drs2 =dtUsers.Select("sex = '男' ");
3.篩選全部性別爲男且年齡在18歲以上的用戶
DataRow[] drs3 =dtUsers.Select("sex = '男' and age >= 18");
4.篩選全部性別爲男或者年齡在18歲以上的用戶
DataRow[] drs4 =dtUsers.Select("sex = '男' or age >= 18");
5.篩選全部姓「夏」的用戶
DataRow[] drs5 =dtUsers.Select("name like '夏%'");
6.篩選全部18歲以上的用戶且按從大到小的順序排序
DataRow[] drs5 =dtUsers.Select("age >=18","age desc");
7.上面最後一種用法沒試過,有機會再列舉出來。
注意事項
1.上面的Select操做是不區分大小寫的(表字段不敏感,如pl-sql語法),若是須要區分大小寫,須要將DataTable的caseSensitive屬性設爲true,例如上表的
dtUsers.CaseSensitive = true;//區分大小寫
2.今天作開發發現一個問題,那邊是對空白符的篩選無效,即dt.Select("colnume = '' ");通過調試後發現是由於個人數據源是從數據庫中查詢的,以下(表名dtOriginal):
我在對PRODUCTUNIT列進行篩選的時候,第一行的「製做一部」篩選出告終果,然後面4行並無,由於是數據類型的問題——
解決辦法有兩種,一種是把全部的空白單元格替換成空格字符 ‘’,一種是在數據庫查詢的時候用decode()函數進行替換,例如SELECT DECODE(列名,NULL,'','列自己') FROM 表名(用replace函數在數據庫中替換NULL是無效的)。
轉載自:https://www.cnblogs.com/programsky/p/4290024.html。
什麼是SQL遊標?
1.1遊標的概念
遊標(Cursor)它使用戶可逐行訪問由SQL Server返回的結果集。使用遊標(cursor)的一個主要的緣由就是把集合操做轉換成單個記錄處理方式。用SQL語言從數據庫中檢索數據後,結果放在內存的一塊區域中,且結果每每是一個含有多個記錄的集合。遊標機制容許用戶在SQL server內逐行地訪問這些記錄,按照用戶本身的意願來顯示和處理這些記錄。
1.2 遊標的優勢
從遊標定義能夠獲得遊標的以下優勢,這些優勢使遊標在實際應用中發揮了重要做用:
1)容許程序對由查詢語句select返回的行集合中的每一行執行相同或不一樣的操做,而不是對整個行集合執行同一個操做。
2)提供對基於遊標位置的表中的行進行刪除和更新的能力。
3)遊標實際上做爲面向集合的數據庫管理系統(RDBMS)和麪向行的程序設計之間的橋樑,使這兩種處理方式經過遊標溝通起來。
1.3 遊標的使用
講了這個多遊標的優勢,如今咱們就親自來揭開遊標的神祕的面紗。
使用遊標的順序: 聲名遊標、打開遊標、讀取數據、關閉遊標、刪除遊標。
1.3.1聲明遊標
最簡單遊標聲明:DECLARE <遊標名>CURSOR FOR;
其中select語句能夠是簡單查詢,也能夠是複雜的接連查詢和嵌套查詢
例子:[已表2 AddSalary爲例子]
Declare mycursor cursor for select * from AddSalary 這樣我就對錶AddSalary申明瞭一個遊標mycursor
【高級備註】
DECLARE <遊標名> [INSENSITIVE] [SCROLL] CURSORFOR 這裏我說一下游標中級應用中的[INSENSITIVE]和[SCROLL]
INSENSITIVE
代表MS SQL SERVER 會將遊標定義所選取出來的數據記錄存放在一臨時表內(創建在tempdb 數據庫下)。對該遊標的讀取操做皆由臨時表來應答。所以,對基本表的修改並不影響遊標提取的數據,即遊標不會隨着基本表內容的改變而改變,同時也沒法經過遊標來更新基本表。若是不使用該保留字,那麼對基本表的更新、刪除都會反映到遊標中。
另外應該指出,當遇到如下狀況發生時,遊標將自動設定INSENSITIVE 選項。
a.在SELECT 語句中使用DISTINCT、 GROUP BY、 HAVING UNION 語句;
b.使用OUTER JOIN;
c.所選取的任意表沒有索引;
d.將實數值看成選取的列。
SCROLL
代表全部的提取操做(如FIRST、 LAST、 PRIOR、 NEXT、 RELATIVE、 ABSOLUTE)均可用。若是不使用該保留字,那麼只能進行NEXT 提取操做。因而可知,SCROLL 極大地增長了提取數據的靈活性,能夠隨意讀取結果集中的任一行數據記錄,而沒必要關閉再
重開遊標。
1.3.2 打開遊標
很是簡單,咱們就打開剛纔咱們聲明的遊標mycursor
OPEN mycursor
1.3.3讀取數據
參數說明:
NEXT 取下一行的數據,並把下一行做爲當前行(遞增)。因爲打開遊標後,行指針是指向該遊標第1行以前,因此第一次執行FETCH NEXT操做將取得遊標集中的第1行數據。NEXT爲默認的遊標提取選項。
INTO @變量名[,…] 把提取操做的列數據放到局部變量中。列表中的各個變量從左到右與遊標結果集中的相應列相關聯。各變量的數據類型必須與相應的結果列的數據類型匹配或是結果列數據類型所支持的隱性轉換。變量的數目必須與遊標選擇列表中的列的數目一致。
如今咱們就取出mycursor遊標的數據吧!
當遊標被打開時,行指針將指向該遊標集第1行以前,若是要讀取遊標集中的第1行數據,必須移動行指針使其指向第1行。就本例而言,可使用下列操做讀取第1行數據:
Eg: Fetch next from mycursor 或則 Fetch first from mycursor
這樣我就取出了遊標裏的數據,可是光光這樣可不夠,咱們還須要將取出的數據賦給變量
CLOSE mycursor
1.3.5刪除遊標
DEALLOCATE mycursor
轉載自:https://blog.csdn.net/shang_111111/article/details/8183737。
SQL Server數據類型轉換方法
在SQL Server平常的函數、存儲過程和SQL語句中,常常會用到不一樣數據類型的轉換。在SQL Server有兩種數據轉換類型:一種是顯性數據轉換;另外一種是隱性數據轉換。下面分別對這兩種數據類型轉換進行簡要的說明:
1 顯式轉換
顯示轉換是將某種數據類型的表達式顯式轉換爲另外一種數據類型。經常使用的是CAST 和 CONVERT 函數。
CAST: CAST ( expression AS data_type )
CONVERT: CONVERT (data_type[(length)], expression [, style])
參數 expression 是任何有效的 Microsoft SQL Server表達式。data_type 目標系統所提供的數據類型,不能使用用戶定義的數據類型。
2 隱性轉換
隱性轉換對於用戶是不可見的,由SQL Server 引擎自動處理。 隱性轉換自動將數據從一種數據類型轉換成另外一種數據類型。例如,若是一個 smallint 變量和一個 int 變量相比較,這個 smallint 變量在比較前即被隱性轉換成 int 變量。 當從一個 SQL Server 對象的數據類型向另外一個轉換時,一些隱性和顯式數據類型轉換是不支持的。例如,nchar 數值根本就不能被轉換成 image 數值。nchar 只能顯式地轉換成 binary,隱性地轉換到 binary 是不支持的。nchar 能夠顯式地或者隱性地轉換成 nvarchar。
3 隱性轉換的風險
隱性轉換有的時候很是方便,能夠簡化SQL 腳本,可是這裏面也孕育着潛在的風險,可能會出如今腳本一開始運行的時候都是正常的,但卻某一個時間點以後,程序莫名出現錯誤。下面舉一個現實項目中的例子來講明。在SQL Server 2008中有一個表,須要從兩個不一樣的數據表中拉取數據,因爲這兩個數據表屬於不一樣的系統,其主鍵類型是不一樣的,一個是int類型,一個是GUID,一開始想着這兩個均可以轉換成字符類型進行存儲。因此就在表中創建一個nvarchar(50)的混合ID列做爲主鍵。以下圖所示:
一開始拉取的數據並未有GUID的值,都是INT類型轉換過來的數據,因此SQL腳本運行的正常,可是忽然某一次運行時,出現了「在將 nvarchar 值 '4C185367-F004-41FE-8A0A-DB4E819B1FF2' 轉換成數據類型 int 時失敗。」的錯誤。以下圖所示:
定位到腳本,執行的SQL以下:
select * from dbo.Demo where 混合ID=305
其中主鍵中的數據有GUID轉換的字符型,也有INT轉換的字符串,示例數據以下:
可是若是執行下面的SQL,則都是正常執行:
- select * from dbo.Demo where 混合ID=305 and 名稱='INT'
- select * from dbo.Demo where 混合ID=305 and 序號='2'
- select * from dbo.Demo where 混合ID=305 and 序號=2
- select * from dbo.Demo where 混合ID='305' and 名稱='INT'
- select * from dbo.Demo where 混合ID='305'
結果以下:
出現上述錯誤的結果應該是這樣的:
select * from dbo.Demo where 混合ID=305在執行時,SQL Server會將nvarchar類型的隱性轉換成int類型,若是數據中沒有GUID類型的字符,則轉換正常,若是有,當進行GUID字符到INT的隱性轉換時,則轉換失敗。
轉載自:https://blog.csdn.net/qq_37446416/article/details/54861081。
LinQ是什麼?
•LINQ(發音:Link)是語言級集成查詢(Language INtegrated Query)
![](http://static.javashuo.com/static/loading.gif)
var q =
from c in db.Customers
where c.City == "London"
select c;
select * from employee where empno=7376;
SQL Server 分頁方法彙總
PageSize = 30
PageNumber = 201
方法一:(最經常使用的分頁代碼, top / not in)
select top 30 UserId from UserInfo where UserId not in (select top 6000 UserId from UserInfo order by UserId) order by UserId
備註: 注意先後的order by 一致
方法二:(not exists, not in 的另外一種寫法而已)
select top 30 * from UserLog where not exists (select 1 from (select top 6000 LogId from UserLog order by LogId) a where a.LogId = UserLog.LogId) order by LogId
備註:EXISTS用於檢查子查詢是否至少會返回一行數據,該子查詢實際上並不返回任何數據,而是返回值True或False。此處的 select 1 from 也能夠是select 2 from,select LogId from, select * from 等等,不影響查詢。並且select 1 效率最高,不用查字典表。效率值比較:1 > anycol > *
方法三:(top / max, 侷限於使用可比較列排序的時候)
select top 30 * from UserLog where LogId > (select max(LogId) from (select top 6000 LogId from UserLog order by LogId) a ) order by LogId
備註:這裏max()函數也能夠用於文本列,文本列的比較會根據字母順序排列,數字 < 字母(無視大小寫) < 中文字符
方法四:(row_number() over (order by LogId))
select top 30 * from ( select row_number() over (order by LogId) as rownumber,* from UserLog)a where rownumber > 6000 order by LogId
select * from (select row_number()over(order by LogId) as rownumber,* from UserLog)a where rownumber > 6000 and rownumber < 6030 order by LogId
select * from (select row_number()over(order by LogId) as rownumber,* from UserLog)a where rownumber between 6000 and 6030 order by LogId
select * from ( select row_number()over(order by tempColumn)rownumber,* from (select top 6030 tempColumn=0,* from UserLog where 1=1 order by LogId)a )b where rownumber>6000 row_number() 的變體,不基於已有字段產生記錄序號,先按條件篩選以及排好序,再在結果集上給一常量列用於產生記錄序號 以上幾種方法參考http://www.cnblogs.com/songjianpin/articles/3489050.html
備註: 這裏rownumber方法屬於排名開窗函數(sum, min, avg等屬於聚合開窗函數,ORACLE中叫分析函數,參考文章:SQL SERVER 開窗函數簡介 )的一種,搭配over關鍵字使用。
方法五:(offset /fetch next, SQL Server 2012支持)
select * from UserLog Order by LogId offset 6000 rows fetch next 30 rows only
備註: 性能參考文章《SQL Server 2012使用OFFSET/FETCH NEXT分頁及性能測試》
參考文檔:
一、http://blog.csdn.net/qiaqia609/article/details/41445233
二、http://www.cnblogs.com/songjianpin/articles/3489050.html
三、http://database.51cto.com/art/201108/283399.htm
轉自:http://www.cnblogs.com/shengxincai/p/6097588.html。