T-Sql 游标未继续获取
我知道游标是不受欢迎的,我会尽可能避免使用它们,但使用它们可能有一些合法的理由。 我有一个,我正在尝试使用一对游标:一个用于主表,一个用于辅助表。 主表游标在外循环中迭代主表。 辅助表游标在内循环中迭代辅助表。 问题是,主表游标虽然显然在继续并将主键列值 [Fname] 保存到局部变量 @Fname 中,但它没有获取辅助表中相应外键列的行。 对于辅助表,它始终返回外键列值与主表第一行的主键列值匹配的行。
以下是我想要在实际存储过程中执行的操作的一个非常简单的示例。 名称是主表
SET NOCOUNT ON
DECLARE
@Fname varchar(50) -- to hold the fname column value from outer cursor loop
,@FK_Fname varchar(50) -- to hold the fname column value from inner cursor loop
,@score int
;
--prepare primary table to be iterated in the outer loop
DECLARE @Names AS Table (Fname varchar(50))
INSERT @Names
SELECT 'Jim' UNION
SELECT 'Bob' UNION
SELECT 'Sam' UNION
SELECT 'Jo'
--prepare secondary/detail table to be iterated in the inner loop
DECLARE @Scores AS Table (Fname varchar(50), Score int)
INSERT @Scores
SELECT 'Jo',1 UNION
SELECT 'Jo',5 UNION
SELECT 'Jim',4 UNION
SELECT 'Bob',10 UNION
SELECT 'Bob',15
--cursor to iterate on the primary table in the outer loop
DECLARE curNames CURSOR
FOR SELECT Fname FROM @Names
OPEN curNames
FETCH NEXT FROM curNames INTO @Fname
--cursor to iterate on the secondary table in the inner loop
DECLARE curScores CURSOR
FOR
SELECT FName,Score
FROM @Scores
WHERE Fname = @Fname
--*** NOTE: Using the primary table's column value @Fname from the outer loop
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Outer loop @Fname = ' + @Fname
OPEN curScores
FETCH NEXT FROM curScores INTO @FK_Fname, @Score
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT ' FK_Fname=' + @FK_Fname + '. Score=' + STR(@Score)
FETCH NEXT FROM curScores INTO @FK_Fname, @Score
END
CLOSE curScores
FETCH NEXT FROM curNames INTO @Fname
END
DEALLOCATE curScores
CLOSE curNames
DEALLOCATE curNames
这是我得到的结果。 请注意,对于外部循环,它确实显示最新的 Fname,但是当该 Fname 用作 @Fname 从辅助表中获取相关行以进行后续迭代时,它仍然会获取与第一个迭代匹配的行主表的行 (Bob)。
Outer loop @Fname = Bob
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Jim
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Jo
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Sam
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
请让我知道我做错了什么。 提前致谢!
I know that cursors are frowned upon and I try to avoid their use as much as possible, but there may be some legitimate reasons to use them. I have one and I am trying to use a pair of cursors: one for the primary table and one for the secondary table. The primary table cursor iterates through the primary table in an outer loop. the secondary table cursor iterates through the secondary table in the inner loop.
The problem is, that the primary table cursor though apparently proceeding and saving the primary key column value [Fname] into a local variable @Fname, but it does not get the row for the corresponding foreign key column in the secondary table. For the secondary table it always returns the rows whose foreign key column value matches the primary key column value of the first row of the primary table.
Following is a very simplified example for what I want to do in the real stored procedure.
Names is the primary table
SET NOCOUNT ON
DECLARE
@Fname varchar(50) -- to hold the fname column value from outer cursor loop
,@FK_Fname varchar(50) -- to hold the fname column value from inner cursor loop
,@score int
;
--prepare primary table to be iterated in the outer loop
DECLARE @Names AS Table (Fname varchar(50))
INSERT @Names
SELECT 'Jim' UNION
SELECT 'Bob' UNION
SELECT 'Sam' UNION
SELECT 'Jo'
--prepare secondary/detail table to be iterated in the inner loop
DECLARE @Scores AS Table (Fname varchar(50), Score int)
INSERT @Scores
SELECT 'Jo',1 UNION
SELECT 'Jo',5 UNION
SELECT 'Jim',4 UNION
SELECT 'Bob',10 UNION
SELECT 'Bob',15
--cursor to iterate on the primary table in the outer loop
DECLARE curNames CURSOR
FOR SELECT Fname FROM @Names
OPEN curNames
FETCH NEXT FROM curNames INTO @Fname
--cursor to iterate on the secondary table in the inner loop
DECLARE curScores CURSOR
FOR
SELECT FName,Score
FROM @Scores
WHERE Fname = @Fname
--*** NOTE: Using the primary table's column value @Fname from the outer loop
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'Outer loop @Fname = ' + @Fname
OPEN curScores
FETCH NEXT FROM curScores INTO @FK_Fname, @Score
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT ' FK_Fname=' + @FK_Fname + '. Score=' + STR(@Score)
FETCH NEXT FROM curScores INTO @FK_Fname, @Score
END
CLOSE curScores
FETCH NEXT FROM curNames INTO @Fname
END
DEALLOCATE curScores
CLOSE curNames
DEALLOCATE curNames
Here is what I get for the result. Please note that for the outer loop it DOES show the up-to-date Fname, but when that Fname is used as @Fname to fetch the relevant row from the secondary table for the succeeding iterations, it still get the rows that match the first row (Bob) of the primary table.
Outer loop @Fname = Bob
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Jim
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Jo
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Outer loop @Fname = Sam
FK_Fname=Bob. Score=10
FK_Fname=Bob. Score=15
Please let me know what am I do wrong.
Thanks in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
@fName 的值在 :DECLARE curScores CURSOR 处计算,而不是在主循环中计算。
您必须在主循环中声明并释放第二个游标。
The value of @fName is evaluated at :DECLARE curScores CURSOR and not in the primary loop.
You must Declare and then deallocate the secon cursor in the primary loop.
由于一些提示,我能够找到解决方案。
我必须在第一个循环中声明并取消分配辅助游标。 我最初讨厌这样做,因为我认为在循环中分配和释放资源不是一个好主意,但我认为在这种特殊情况下没有其他方法可以避免这种情况。 现在,工作代码看起来像这样:
我得到了正确的结果:
Thanks to few hints, I was able to find the solution.
I had to DECLARE and DEALLOCATE the secondary cursor within the first loop. I initially hated to do it as I thought alocating and deallocating resources in the loop was not a good idea, but I think there is no other way to avoid this in this particular situation. Noew the working code looks some thing like this:
And I am getting the right results:
我认为使用具有行号的临时表可以更轻松地做到这一点:
看起来您确实要求 SQL 表现得像一种喜欢循环的语言。 事实并非如此。 每当我发现自己在 SQL 中编写循环时,我就会问自己,是否必须这样做? 7/10 次答案是否定的,我可以用集合来代替。
I think you could do this so much easier with temp tables that have row numbers:
It really looks like you're asking SQL to behave like a language that likes loops. It doesn't. Whenever I find myself writing a loop in SQL I ask myself, does it have to be done this way? 7/10 times the answer is no, I can do it with sets instead.
我会尝试将其放在
第一个 while 内,因为您只为第一个名称值声明光标
I'd try placing the
inside the first while, beacuse you're declaring the cursor only for the first name value