2009-04-30 88 views
63

如何將選定的字段值從查詢存儲到變量中並在更新語句中使用它?如何將選擇結果分配給變量?

這裏是我的方法:

我正在寫一個SQL Server 2005的T-SQL存儲過程,它執行以下操作:

  1. 被從發票表發票ID和店鋪列表光標
  2. 從遊標讀取發票ID - > tmp_key可變
  3. 的foreach tmp_key發現從客戶表客戶發票主接觸ID
  4. 更新客戶端接觸與主接觸ID鍵
  5. 接近光標

這裏是我的代碼:

DECLARE @tmp_key int 
DECLARE @get_invckey cursor 

set @get_invckey = CURSOR FOR 
    select invckey from tarinvoice where confirmtocntctkey is null and tranno like '%115876' 

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey into @tmp_key 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT c.PrimaryCntctKey as PrimaryContactKey 
    from tarcustomer c, tarinvoice i 
    where i.custkey = c.custkey and i.invckey = @tmp_key 

    UPDATE tarinvoice set confirmtocntctkey = PrimaryContactKey where invckey = @tmp_key 
    FETCH NEXT FROM @get_invckey INTO @tmp_key 
END 

CLOSE @get_invckey 
DEALLOCATE @get_invckey 

如何存儲PrimaryContactKey及以下update語句的set子句中再次使用它?我是否創建一個遊標變量或只是一個int類型的另一個局部變量?

+2

如下面@GilaMonster答案,這整個操作可以是單一的UPDATE語句( 「基於設定操作」,不與[T-SQL SET語句]混淆(HTTPS ://msdn.microsoft.com/en-us/library/ms189484.aspx))這是一個更好的方法(更快的執行,更少的開銷和更少的代碼)。我只是指出了這一點,因爲這個問題和所有當前最重要的答案都是關於如何編寫SET語句,但它並不是最好的開始。 – gregmac 2015-02-24 17:15:30

回答

40
DECLARE @tmp_key int 
DECLARE @get_invckey cursor 

SET @get_invckey = CURSOR FOR 
    SELECT invckey FROM tarinvoice WHERE confirmtocntctkey IS NULL AND tranno LIKE '%115876' 

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey INTO @tmp_key 

DECLARE @PrimaryContactKey int --or whatever datatype it is 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT @PrimaryContactKey=c.PrimaryCntctKey 
    FROM tarcustomer c, tarinvoice i 
    WHERE i.custkey = c.custkey AND i.invckey = @tmp_key 

    UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey WHERE invckey = @tmp_key 
    FETCH NEXT FROM @get_invckey INTO @tmp_key 
END 

CLOSE @get_invckey 
DEALLOCATE @get_invckey 

編輯:
這個問題已經得到了很多更多的牽引力比我預料。請注意,我不是主張在我的答案中使用光標,而是顯示如何根據問題分配值。

18

嘗試這個

SELECT @PrimaryContactKey = c.PrimaryCntctKey 
FROM tarcustomer c, tarinvoice i 
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key 

UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey 
WHERE invckey = @tmp_key 
FETCH NEXT FROM @get_invckey INTO @tmp_key 

您將宣佈你的循環之外這個變量只是一個標準的TSQL變量。

我也應該注意到,這是如何做到這一點的任何類型的選擇到一個變量,而不只是當處理遊標。

13

爲什麼你需要一個光標? 您的整個代碼段可以被替換,這將在大量行上運行得更快。

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey 
WHERE confirmtocntctkey is null and tranno like '%115876' 
+0

遊標是否真的皺起了眉頭? – phill 2009-05-04 14:11:20

+4

他們很慢。 SQL Server針對基於集合的查詢進行了優化。在一個查詢中運行一百萬行比運行一百萬行更快。除此之外,遊標所具有的開銷,並且您通過使用遊標而不是基於集合的操作來要求主要性能問題 測試您的遊標解決方案和查詢,查看兩者的執行時間。 – GilaMonster 2009-05-08 08:53:50

+0

謝謝男人!!!!這樣做對我來說,比解決如何更改我的特定場景的光標更容易。你是冠軍! – 2015-05-22 11:23:14

81

我只是有同樣的問題,...

declare @userId uniqueidentifier 
set @userId = (select top 1 UserId from aspnet_Users) 

甚至更​​短:

declare @userId uniqueidentifier 
SELECT TOP 1 @userId = UserId FROM aspnet_Users 
9

爲了安全地分配一個變量,你必須使用SET-SELECT聲明:

SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey 
    FROM tarcustomer c, tarinvoice i 
    WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key) 

請確保你有既有開始也有結束括號!

SET-SELECT版本是設置變量最安全的方法的原因是雙重的。

1。SELECT返回多個帖子

如果以下選擇結果在多個帖子中會發生什麼?

SELECT @PrimaryContactKey = c.PrimaryCntctKey 
FROM tarcustomer c, tarinvoice i 
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key 

@PrimaryContactKey會從結果過去後被分配的值。

實際上,@PrimaryContactKey將在結果中爲每個帖子分配一個值,因此它將包含SELECT命令正在處理的最後一個帖子的值。

哪個帖子是「最後一個」是由任何聚簇索引決定的,或者如果沒有使用聚簇索引或者主鍵是聚簇的,則「最後」帖子將是最近添加的帖子。在最壞的情況下,這種行爲可能會在每次索引表改變時被改變。

使用SET-SELECT語句,您的變量將被設置爲null

2. SELECT沒有返回崗位

會發生什麼,使用的代碼的第二個版本時,如果您選擇不返回的結果呢?

與您可能認爲的相反,變量的值不會爲空 - 它會保留它是以前的值!

這是因爲,如前所述,SQL將值賦給變量後每一次 - 這意味着如果結果不包含任何職位也不會做任何變量。所以,變量在運行語句之前仍然具有它的價值。

使用SET-SELECT語句,值將爲null

參見:SET versus SELECT when assigning variables?