我不明白发生了什么。
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-09-10',Second'SELECT @X'必须返回'NULL'但Second返回'2012-09-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-09-10',然后下一个
Projectcode = 130192
,@ProjectContractDate_T0
必须为NULL,但为“2012-09-10”。怎么可能?
在while循环中,为什么ProjectContractDate_T0
没有重置为NULL?
答案 0 :(得分:3)
当select的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分配null。
这是另一个例子
DECLARE @x NVARCHAR(25) = 'Initial value'
SELECT @x = 'Value1'
WHERE 0 = 1
--@x is still "Initial value" cause 0 isn't egal to 1
SELECT @x = (SELECT 'Value2'
WHERE 0 = 1)
--@x 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引擎的一条指令行。
旁注:
您的"选择"可以用"#by顺序重写。和" TOP 1"条款得到最低限度。它给出了相同的结果,写入/读取的时间更短。
SELECT @ProjectContractDate_T0 = (SELECT TOP 1 ContractDate
FROM dbo.FooFoo C
WHERE ProjectCode = @ProjectCode
ORDER BY VersionID)
它做同样的事情。
答案 1 :(得分:2)
在select语句中设置变量时,如果select语句没有返回任何行,则不会有赋值;你的变量的值不会改变。
关于循环问题,T-SQL中变量的范围是批处理,而不是循环。每次迭代都不会重新声明或初始化。
因此,在T-SQL中,如果您希望在其他语言中重新初始化,则将变量显式初始化为null是一种很好的做法。这可能会使其更具可读性并更好地显示您的意图。
另外,我应该补充说,当基于集合的解决方案(查询)成为可能时,通常最好避免使用T-SQL中的游标和循环,这几乎总是如此。显然这取决于你的使用案例,但没有说明。