2016-07-27 66 views
0

我不明白髮生了什麼事情。如何在SELECT語句中將聲明變量的NULL值設置爲?

DECLARE @X DATETIME; 

--FIRST 
SELECT @X = ContractDate 
FROM dbo.Foo C 
WHERE ProjectCode = 120125 
    AND VersionID = (SELECT MIN(VersionID) 
        FROM dbo.Foo 
        WHERE ProjectCode = C.ProjectCode) 

SELECT @X 

--SECOND 
SELECT @X = ContractDate 
FROM dbo.Foo C 
WHERE ProjectCode = 130192 
    AND VersionID = (SELECT MIN(VersionID) 
        FROM dbo.Foo 
        WHERE ProjectCode = C.ProjectCode) 

SELECT @X 

第一 'SELECT @X' 必須返回 '2012年9月10日',Second'SELECT @X」必須返回 'NULL',但第二個返回 '2012年9月10日'。

第一個問題:爲什麼第二個'SELECT @X'返回NULL?

上面的代碼塊在WHILE語句中。原來的代碼是在這裏:

DECLARE @ProjectCode NVARCHAR(10) 

DECLARE CRS CURSOR FOR 
    SELECT P.ProjectCode 
    FROM dbo.Foo P 

OPEN CRS 

FETCH NEXT FROM CRS INTO @ProjectCode 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    DECLARE @ProjectContractDate_T0 DATETIME; 

    SELECT @ProjectContractDate_T0 = ContractDate 
    FROM dbo.FooFoo C 
    WHERE ProjectCode = @ProjectCode 
     AND VersionID = (SELECT MIN(VersionID) 
         FROM dbo.FooFoo 
         WHERE ProjectCode = C.ProjectCode) 

    SELECT @ProjectContractDate_T0 

    FETCH NEXT FROM CRS INTO @ProjectCode 
END 

CLOSE CRS 
DEALLOCATE CRS 

while循環處理:

  • ProjectCode = 120125@ProjectContractDate_T0是 '2012年9月10日',

那麼接下來

  • Projectcode = 130192@ProjectContractDate_T0必須爲NULL,但爲'2012-09-10'。

這怎麼可能?

在while循環中,爲什​​麼ProjectContractDate_T0重置爲NULL?

+0

你需要打印出所有的值和調試,我把它看作是數據相關的,我們對涉及的數據沒有任何想法 – TheGameiswar

+1

這是一個經典的關於數據庫的「過程式」方法,並不像說明錯誤的代碼那樣具有建設性。它應該是: SELECT P.ProjectCode,C.ContractDate FROM dbo.Foo P LEFT OUTER JOIN dbo.FooFooÇ ON( C.ProjectCode = P.ProjectCode AND C.VersionID =( SELECT MIN (VERSIONID) FROM dbo.FooFoo變量C_min WHERE C_Min.ProjectCode = P.ProjectCode ) –

回答

3

當選擇的where子句篩選出每條記錄時,則不進行分配。因此,@x具有最後一次分配的值。

嘗試,而不是這樣:

SELECT @X = (SELECT ContractDate 
      FROM dbo.Foo C 
      WHERE ProjectCode = 130192 
      AND VersionID = (SELECT MIN(VersionID) 
           FROM dbo.Foo 
           WHERE ProjectCode = C.ProjectCode)) 

這樣,你的分配「選擇」不含有任何在where子句,因此它總是會被執行。如果內部的選擇不會產生任何東西,然後空被分配到X.

下面是另一個例子

DECLARE @x NVARCHAR(25) = 'Initial value' 

SELECT @x = 'Value1' 
WHERE 0 = 1 

[email protected] is still "Initial value" cause 0 isn't egal to 1 

SELECT @x = (SELECT 'Value2' 
      WHERE 0 = 1) 

[email protected] is now null because the impossible where clause didn't hindered the assignation. It has just made the inner select to return null instead. 

正如馬丁建議,你可以用之前代替重置價值

SELECT @X = null 

但我更喜歡只有一個分配選擇,因爲它更短,並且它是SQL引擎的少一個指令行。


旁註:

你 「選擇」 可以用一個和 「TOP 1」 條款 「按訂單」,以獲得最低改寫。它給出了相同的結果,並且寫入/讀取的時間更短。

SELECT @ProjectContractDate_T0 = (SELECT TOP 1 ContractDate 
            FROM dbo.FooFoo C 
            WHERE ProjectCode = @ProjectCode 
            ORDER BY VersionID) 

它做同樣的事情。

+3

是的,或只是reinitilaise'@ X'到零之前第二選擇。 –

+0

非常感謝。我發現喜歡你的報價。我寫道:SET @X =(SELECT ContractDate FROM dbo.Foo C WHERE ProjectCode = 130192 AND VersionID =(SELECT MIN(VersionID) FROM dbo.Foo WHERE ProjectCode = C.ProjectCode))謝謝AXMIM,馬丁 – hebset

+0

AXMIM,您的側面說明非常有用,非常感謝。 – hebset

2

在select語句中設置變量時,如果select語句不返回任何行,那麼將不會有任何賦值;你的變量的值不會改變。

至於你的循環問題,T-SQL中變量的作用域是批處理,而不是循環。每次迭代都不重新聲明或初始化。

因此,在其他情況下可能需要重新初始化時,在T-SQL中顯式初始化變量爲null可能是一個好習慣。這可能會使其更具可讀性並更好地表達您的意圖。

另外,我應該補充說,在基於集合的解決方案(查詢)是可能的時候,通常最好避免T-SQL中的遊標和循環,而這幾乎總是存在。顯然這取決於你的用例,這是沒有說明的。

+0

'至於你的循環問題,T-SQL中變量的範圍是批處理,而不是循環。它不會在每次迭代時重新聲明或初始化。'我也是這麼想。謝謝蒂姆。 – hebset