SELECT INTO創建臨時表
SQL Server臨時表有兩種類型:本地和全局。它們在名稱、可見性以及可用性上有區別。本地臨時表的名稱以單個數字符號 (#)
打頭;它們僅對當前的用戶連接是可見的;當用戶從 SQL Server 實例斷開連接時被刪除。全局臨時表的名稱以兩個數字符號 (##)
打頭,創建后對任何用戶都是可見的,當所有引用該表的用戶從 SQL Server 斷開連接時被刪除。
如果數據庫會話創建了本地臨時表 #temtable,則僅會話可以使用該表,會話斷開連接后就將該表刪除。如果創建了
##temtable全局臨時表,則數據庫中的任何用戶均可使用該表。如果該表在您創建后沒有其他用戶使用,則當您斷開連接時該表刪除。如果您創建該表后另一個用戶在使用該表,則SQL Server 將在您斷開連接並且所有其他會話不再使用該表時將其刪除。
如果本地臨時表由存儲過程創建或由多個用戶同時執行的應用程序創建,則SQL Server 必須能夠區分由不同用戶創建的表。為此,SQL Server 在內部為每個本地臨時表的表名追加一個數字后綴。存儲在tempdb 數據庫的 sysobjects 表中的臨時表,其全名由 CREATE TABLE 語句中指定的表名和系統生成的數字后綴組成。為了允許追加后綴,為本地臨時表指定的表名table_name不能超過 116 個字符。
當存儲過程完成時,將自動除去在存儲過程中創建的本地臨時表。由創建表的存儲過程執行的所有嵌套存儲過程都可以引用此表。但調用創建此表的存儲過程的進程無法引用此表。
臨時表位於tempdb系統數據庫。
使用SELECT INTO語句可以把任何查詢結果集放置到一個新表中,還可以通過使用SELECT
INTO語句解決復雜的問題。例如,需要從不同數據源中得到數據集,如果一開始先創建一個臨時表,那么在該表上執行查詢比在多表或多數據庫中執行查詢更簡單。
在使用SELECT INTO語句時,應該注意如下的事項和原則:
可以使用SELECT INTO語句創建一個表並且在單獨操作中向表中插入行。確保在SELECT INTO語句中指定的表名是惟一的。如果表名出現重復,SELECT
INTO語句將失敗。
可以創建本地或全局臨時表。要創建一個本地臨時表,需要在表名前加符號(#);要創建一個全局臨時表,需要在表名前加兩個符號(##)。本地臨時表只在當前的會話中可見,全局臨時表在所有的會話中都可見。
當使用者結束會話時,本地臨時表的空間會被回收。
當創建表的會話結束且當前參照表的最后一個Transact-SQL語句完成時,全局臨時表的空間會被回收。
使用SELECT INTO語句的基本語法如下:
SELECT <select_list>
INTO new_table
FROM {<table_source>}[,…n]
WHERE <search_condition>
例如:select * into #newTable from news where s_date>'2010-3-1'
利用SQL Server的全局臨時表防止用戶重復登錄
在我們開發商務軟件的時候,常常會遇到這樣的一個問題:怎樣防止用戶重復登錄我們的系統?特別是對於銀行或是財務部門,更是要限制用戶以其工號身份多次登入。
可能會有人說在用戶信息表中加一字段判斷用戶工號登錄的狀態,登錄后寫1,退出時寫0,且登錄時判斷其標志位是否為1,如是則不讓該用戶工號登錄。但是這樣那勢必會帶來新的問題:如發生象斷電之類不可預知的現象,系統是非正常退出,無法將標志位置為0,那么下次以該用戶工號登錄則不可登入,這該怎么辦呢?
或許我們可以換一下思路:有什么東西是在connection斷開后可以被系統自動回收的呢?對了,SQL
Server的臨時表具備這個特性!但是我們這里的這種情況不能用局部臨時表,因為局部臨時表對於每一個connection來說都是一個獨立的對象,因此只能用全局臨時表來達到我們的目的。
好了,情況已經明朗話了,我們可以寫一個象下面這樣簡單的存儲過程:
create procedure gp_findtemptable -- 2001/10/26 21:36 zhuzhichao in nanjing
/* 尋找以操作員工號命名的全局臨時表
* 如無則將out參數置為0並創建該表,如有則將out參數置為1
* 在connection斷開連接后,全局臨時表會被SQL Server自動回收
* 如發生斷電之類的意外,全局臨時表雖然還存在於tempdb中,但是已經失去活性
* 用object_id函數去判斷時會認為其不存在. */
@v_userid varchar(6), -- 操作員工號
@i_out int out -- 輸出參數 0:沒有登錄 1:已經登錄
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
在這個過程中,我們看到如果以用戶工號命名的全局臨時表不存在時過程會去創建一張並把out參數置為0,如果已經存在則將out參數置為1。
這樣,我們在我們的應用程序中調用該過程時,如果取得的out參數為1時,我們可以毫不客氣地跳出一個message告訴用戶說”對不起,此工號正被使用!”
判斷方法范例:
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 " )
end
else
set @sTmpWareA="[##MARWareA"+ @ComputerName+"]"
@sTmpWareA 就是臨時表的名稱,過程中使用exec來操作