SQL Server臨時(shí)表的使用方案大全
我們今天是要和大家一起討論的是SQL Server臨時(shí)表的實(shí)用大全,如果你對(duì)SQL Server臨時(shí)表的實(shí)用大全不是很了解的話,下面的文章就是對(duì)其相關(guān)內(nèi)容的具體介紹,希望會(huì)給你帶來(lái)一些幫助在此方面。
引子:
臨時(shí)數(shù)據(jù)表格,我們?cè)诖鎯?chǔ)的時(shí)候經(jīng)常遇見(jiàn)。
客戶(hù)端可以實(shí)用Delphi的ClientDataSet的內(nèi)存表,但是ClientDataSet類(lèi)似TABLE,不是支持SQL語(yǔ)言的。
當(dāng)然也可以實(shí)用臨時(shí)表。有時(shí)我們避免SQL Server臨時(shí)表的生命周期的麻煩,更多的使用實(shí)際表臨時(shí)用用。起個(gè)什么tempXXX類(lèi)似的告訴我們他們是臨時(shí)表。創(chuàng)建釋放也沒(méi)有問(wèn)題。
那么臨時(shí)表的周期是什么樣子的呢?有什么特殊的用法沒(méi)有?
1.全局臨時(shí)表和臨時(shí)表的區(qū)別:視野不同。
全局臨時(shí)表當(dāng)然就是使用##打頭的表格,普通的臨時(shí)表格為#打頭。它們的周期應(yīng)該隨一個(gè)連接也就是Connection的誕生而生,隨著Connection的斷開(kāi)而死亡。它們的區(qū)別不同的地方也就是視野不同。
全局表,全部授權(quán)的Connection都可以看見(jiàn)。但是普通SQL Server臨時(shí)表(局域臨時(shí)表)僅僅創(chuàng)建的Connection可以看見(jiàn)。特別說(shuō)明的是SQL Server的isql.exe每個(gè)連接就是一個(gè)Connection。
例如:一個(gè)應(yīng)用程序app.exe有僅adoconnection連接SQL Server數(shù)據(jù),那么這個(gè)連接中的adoquery或者存儲(chǔ)過(guò)程建立的全局表##temp1,另外的一個(gè)app.exe或者其它的appx.exe都可以使用該表格。
不同的是普通臨時(shí)表,由app.exe中的連接connection比如adoconnection的Adoquery建立的臨時(shí)表#temp,在所有該連接的該程序的app.exe都可以看見(jiàn)并且訪問(wèn),但是appx.exe或者其它的就不能看見(jiàn)。
陷阱:如果一個(gè)應(yīng)用程序app.exe有存儲(chǔ)過(guò)程和TADOQUERY連接同一個(gè)ADOCONNECTION.切記使用存儲(chǔ)過(guò)程建立的臨時(shí)表(非全局),就不能被這個(gè)連接下的TADOQUERY訪問(wèn)。原因是:存儲(chǔ)過(guò)程本身是服務(wù)器端執(zhí)行,應(yīng)該是服務(wù)器的CONNECTION。
2.全局表或者SQL Server臨時(shí)表的存儲(chǔ)和建立。
估計(jì)大家都知道,臨時(shí)表或者全局表都是在SQL Server的tempdb數(shù)據(jù)庫(kù)存儲(chǔ),表我們?cè)L問(wèn)的時(shí)候使用#,但是實(shí)際在進(jìn)程里面是以在tempdb里面的用戶(hù)表以#xxx_________00000000xxx方式存儲(chǔ)(是否是進(jìn)程標(biāo)識(shí),不大知道,也不想知道)。可以通過(guò)isql.exe的tempdb里面看見(jiàn)它們。
3。頭痛初始化表格
初始化表格,為什么頭痛,畢竟使用Drop什么的。或者判斷存在比較麻煩。其實(shí)也很簡(jiǎn)單。另外建立臨時(shí)表,都是無(wú)聊的SQL 語(yǔ)句,怎么處理。
方法一:當(dāng)然是使用存儲(chǔ)過(guò)程了。可以直接寫(xiě)SQL語(yǔ)句或者寫(xiě)exec (@v_sql)。
方法二:把SQL Server臨時(shí)表保存到數(shù)據(jù)里面MEMO里面,讀取,直接執(zhí)行。
判斷方法一:可以采用常用的exists函數(shù)。
例如:
- if exists (select * from tempdb..sysobjects where id = object_id(@sTmpWareA) and type = "U")
判斷方法二:
- if object_id('tempdb.dbo.##'+@v_userid) is null
應(yīng)用方法一:(感謝阿滿,迷糊)
一個(gè)統(tǒng)計(jì)的SQL Server臨時(shí)表格,使用TADOPROC執(zhí)行存儲(chǔ)過(guò)程,如下:
- CREATE PROCEDURE InitCreateCoawardTable AS
- BEGIN
- IF not (object_id('tempdb.dbo.#Tmp_Detail') is null)
- drop table tempdb.dbo.#Tmp_Detail
- CREATE TABLE tempdb.dbo.#Tmp_Detail (
- [id] [int] IDENTITY (1, 1) NOT NULL ,
[單據(jù)類(lèi)別] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[單據(jù)編號(hào)] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
(。。這里多復(fù)雜都可以。。。。。省略。。。)
- select * from tempdb.dbo.#Tmp_Detail
- END
- GO
在客戶(hù)端使用TADOPROC執(zhí)行這個(gè)存儲(chǔ)過(guò)程,
- with sproc do
- begin
- try
- Close;
- ProcedureName:=spName;
- Parameters.Refresh;
- Prepared;
- ExecProc;
Open;//這句不能省略要不,就出現(xiàn)忽略了數(shù)據(jù)庫(kù)名稱(chēng) ',將引用 tempdb 中的對(duì)象錯(cuò)誤。
- except
- Close;
- Exit;
- end;
- Result:=True;
- end;
這樣,你的TADOPROC就可以任意使用APPEND,INSERT語(yǔ)句了,更好的是不需要清理,而且方法靈活。更好的有點(diǎn)非常有效的處理并發(fā)。當(dāng)然有些人還在使用建立實(shí)際表格代替它,使用會(huì)話處理該問(wèn)題,你還得回收。相當(dāng)麻煩。而且靈活度差多了。
以下是應(yīng)用范例轉(zhuǎn)載:
利用SQL Server的全局臨時(shí)表防止用戶(hù)重復(fù)登錄
在我們開(kāi)發(fā)商務(wù)軟件的時(shí)候,常常會(huì)遇到這樣的一個(gè)問(wèn)題:怎樣防止用戶(hù)重復(fù)登錄我們的系統(tǒng)?特別是對(duì)于銀行或是財(cái)務(wù)部門(mén),更是要限制用戶(hù)以其工號(hào)身份多次登入。
可能會(huì)有人說(shuō)在用戶(hù)信息表中加一字段判斷用戶(hù)工號(hào)登錄的狀態(tài),登錄后寫(xiě)1,退出時(shí)寫(xiě)0,且登錄時(shí)判斷其標(biāo)志位是否為1,如是則不讓該用戶(hù)工號(hào)登錄。但是這樣那勢(shì)必會(huì)帶來(lái)新的問(wèn)題:如發(fā)生象斷電之類(lèi)不可預(yù)知的現(xiàn)象,系統(tǒng)是非正常退出,無(wú)法將標(biāo)志位置為0,那么下次以該用戶(hù)工號(hào)登錄則不可登入,這該怎么辦呢?
或許我們可以換一下思路:有什么東西是在connection斷開(kāi)后可以被系統(tǒng)自動(dòng)回收的呢?對(duì)了,SQL Server的臨時(shí)表具備這個(gè)特性!但是我們這里的這種情況不能用局部臨時(shí)表,因?yàn)榫植颗R時(shí)表對(duì)于每一個(gè)connection來(lái)說(shuō)都是一個(gè)獨(dú)立的對(duì)象,因此只能用全局SQL Server臨時(shí)表來(lái)達(dá)到我們的目的。
好了,情況已經(jīng)明朗話了,我們可以寫(xiě)一個(gè)象下面這樣簡(jiǎn)單的存儲(chǔ)過(guò)程:
- create procedure gp_findtemptable -- 2001/10/26 21:36 zhuzhichao in nanjing
/* 尋找以操作員工號(hào)命名的全局臨時(shí)表
* 如無(wú)則將out參數(shù)置為0并創(chuàng)建該表,如有則將out參數(shù)置為1
* 在connection斷開(kāi)連接后,全局臨時(shí)表會(huì)被SQL Server自動(dòng)回收
* 如發(fā)生斷電之類(lèi)的意外,全局臨時(shí)表雖然還存在于tempdb中,但是已經(jīng)失去活性
* 用object_id函數(shù)去判斷時(shí)會(huì)認(rèn)為其不存在. */
@v_userid varchar(6), -- 操作員工號(hào)
@i_out int out -- 輸出參數(shù) 0:沒(méi)有登錄 1:已經(jīng)登錄
- as
- declare @v_sql varchar(100)
- if object_id('tempdb.dbo.##'+@v_userid) is null
- begin
- set @v_sql = 'create table ##'+@v_userid+'(userid varchar(6))'
- exec (@v_sql)
- set @i_out = 0
- end
- else
- set @i_out = 1
在這個(gè)過(guò)程中,我們看到如果以用戶(hù)工號(hào)命名的全局SQL Server臨時(shí)表不存在時(shí)過(guò)程會(huì)去創(chuàng)建一張并把out參數(shù)置為0,如果已經(jīng)存在則將out參數(shù)置為1。
這樣,我們?cè)谖覀兊膽?yīng)用程序中調(diào)用該過(guò)程時(shí),如果取得的out參數(shù)為1時(shí),我們可以毫不客氣地跳出一個(gè)message告訴用戶(hù)說(shuō)”對(duì)不起,此工號(hào)正被使用!”
判斷方法范例:
- select @sTmpWareA="tempdb..[##MARWareA"+ @ComputerName+"]"
- if exists (select * from tempdb..sysobjects where id = object_id(@sTmpWareA) and type = "U")
- begin
- set @sTmpWareA="[##MARWareA"+ @ComputerName+"]"
- exec( "drop table " +@sTmpWareA )
- end
- else
- set @sTmpWareA="[##MARWareA"+ @ComputerName+"]"
@sTmpWareA 就是SQL Server臨時(shí)表的名稱(chēng),過(guò)程中使用exec來(lái)操作