在上次讨论了declare变量的作用域以后我们继续深入谈论一下,准确的说是我有些疑惑想跟大家讨论,有高手明白的话指点一下。
关于作用域的谈论:
这个问题不太好解释,大家看一段代码,在循环中定义表变量。
注意 代码使用Northwind数据库,需要Northwind库的请访问
DECLARE @id INT
DECLARE myCURSOR CURSOR FOR
SELECT TOP 3 c.CategoryID FROM Categories c
OPEN myCURSOR
FETCH NEXT FROM myCURSOR INTO @id
WHILE @@FETCH_STATUS = 0
BEGIN
--当前循环的id输出
SELECT @id
DECLARE @TessTable TABLE (
[name] NVARCHAR(40)
)
--DELETE FROM @TessTable
INSERT INTO @TessTable
SELECT p.ProductName
FROM Products p
WHERE p.CategoryID=@id
--当前循环的id下所有的产品名称输出
SELECT * FROM @TessTable
FETCH NEXT FROM myCURSOR INTO @id
END
CLOSE myCURSOR
DEALLOCATE myCURSOR
END
逻辑比较简单,就是从分类表(Categories)中取出所有分类的id,游标循环所有id,依次把每个类别的商品名称放到表变量中显示出来,这个查询没有实际意义就是为了展示一下问题,对代码本身的优劣不做过多要求。
不知道大家看了这个查询后想象到的输出结果应该是什么样的?我认为结果是每次循环输出两个表,第一个是SELECT @id的结果输出当前循环到的CategoryID ,另一个是SELECT * FROM @TessTable的结果输出属于@id的所有产品的名称
举例来说:
比如我们现在有数据:
Categories表
CategoryID | Name |
1 | Beverages |
2 | Condiments |
Products
Id | ProductName | CategoryID |
1 | Chai | 1 |
2 | Chang | 1 |
3 | Aniseed Syrup | 2 |
注意
表结构是我随意捏造的跟Northwind略有不同
这样的数据那我认为的输出的两个表,以第1次循环来应该是
| 无名列 |
1 | 1 |
| Name |
1 | Chai |
2 | Chang |
实际截图:
第二次循环的第一个输出表的内容就应该是2,二个输出表应该就一项应该是Aniseed Syrup,不知道多少人跟我想的一样,可惜的是有多少人跟我想的一样就有多少人错了。
实际的结果第二次循环的输出内容为:
| 无名列 |
1 | 2 |
| Name |
1 | Chai |
2 | Chang |
3 | Aniseed Syrup |
第二次的查询结果是追加在第一次查询结果的表变量里的,为什么这样,我只能猜测,第一次循环时定义了表变量,因为declare的作用域是整个批处理,所以第二次循环是declare语句就不在执行了,当然这没什么理论依据,只是根据查询推断出来的,按说定义了一个变量再一次定义同名变量,应该会有错误,但是以上代码可以完好只执行,放到try里面也捕捉不到错误,哪位大虾能说清具体原理的指教一下小弟。
如果你想得到正确的结果那就把declare下面那句delete打开,每次都清一下数据结果就是正确的了。
说完表变量,那大家想象如果是变量做这样的操作,会不会累加啊?我上代码:
DECLARE @i INT
SET @i=1
WHILE @i<6
BEGIN
PRINT 'i:'+cast(@i AS nVARCHAR)
DECLARE @t VARCHAR
-- set @t='0'
SET @t='a'+@t+cast(@i AS nVARCHAR)
PRINT 't:'+cast(@t AS nVARCHAR)
SET @i=@i+1
END
GO
猜谜继续啊,你们猜猜是什么结果。
我直接说好了
i:1
i:2
i:3
i:4
i:5
这就是结果,根本没有print @t的内容,而且同样放到try里面不报错
这句--set @t='0'打开给@t赋一个初始值的话下面就就可以输出了但是结果依然很神奇
i:1
t:a
i:2
t:a
i:3
t:a
i:4
t:a
i:5
t:a
谁能告诉我为什么?