如何用光标找到每个客户的第四个订单 [英] how to find the 4th order for each customer with cursor
问题描述
我想找到每个客户的第4个订单及其所有订单之间的Title_order(按订单日期排序)。如果他们没有订单或少于4返回NULL。使用Cursor限制它。我创建了这个,但是给我回复了所有订单。
我有桌子
顾客filds fname,lname,Id_customer
订购filds ID_order,date,title_order
ALTER function [dbo]。[f4order]( @ id_customer int , @ID_order int )
返回 varchar ( 255 )
as 开始
声明 @ row3 as int , @ data as date , @ 4order as varchar ( 50 )
DECLARE myCursor CURSOR FOR
选择 ID_order
来自(选择 ID_order,ROW_NUMBER() over (订单 按 DATE desc ) as row 来自 订单
其中 Id_customer = @ id_customer) as tmp
其中行= 4
打开 myCu rsor;
FETCH NEXT FROM myCursor INTO @ row4
WHILE @@ FETCH_STATUS = 0
开始
if (@ row4 = @ ID_order )
begin
set @ 4order =(选择编号来自 订单 其中 @ ID_order = ID_order)
结束
else
set @ 4order = ' null'
FETCH NEXT FROM myCursor INTO @ row4 ;
end
CLOSE myCursor
DEALLOCATE myCursor
return @ 4order
end
;
不知道是否可以完成
提前谢谢
我终于得到了你的代码,一旦我得到了正确的答案修复了所有错误......
ORDER
和DATE
是保留字,所以如果您要将它们用作表格或列名称,则必须用方括号括起来,即[order],[DATE]
。更好的是,选择不同的名字。您也没有声明@ row4
。
在您提供的代码中,不需要游标因为你已经使用ROW_NUMBER
意味着你可以直接定位第4行 - 这实际上就是你用做的事情,其中row = 4
注意:形成游标的查询只返回一行,因为你有FETCH NEXT
一个ELSE
子句。如果您打算使用光标,请确保总是获取下一行,否则您可能会无限循环。
以下简单的示例显示如何使用游标在查询中查找第4行(CAVEAT - 这不是推荐的方法,仅用于演示光标)
我设置了一些样本数据,其中包含一个数字为1到19的int和一个包含一些文本的varchar列(单词'text'后跟与id相同的数字)
< pre lang =SQL> 创建 table cursorExample
(
id int identity ( 1 , 1 ),
someData varchar (max)
)
声明 @ i int = 1
while @ i < 20
开始
insert into cursorExample values (' text' + cast( @ i as varchar ))
set @ i = @ i + 1
end
现在想象一下,我想找到该表末尾的第4行。即此查询的第4行选择 id,someData 来自 cursorExample 订单 按 id DESC
我可以使用以下sql声明 @myInt int
声明 @myVarchar varchar (max)
声明 @ myDesiredInt int = 4
声明 @ myFoundVarchar varchar (max)
声明 @ myFoundInt int
声明 @ loopCount int = 1
声明 myCursor cursor
选择 id,someData 来自 cursorExample order 按 id DESC
打开 myCursor
获取下一步来自 myCursor 进入 @ myInt , @ myVarChar
while @@ FETCH_STATUS = 0
begin
print cast( @ loopCount as varchar )+ ' :'
+ @ myVarChar + ' :' + cast( @myInt as varchar )+ ' :'
+ isnull(cast( @ myFoundInt as varchar ),' null')+ ' :'
+ isnull( @ myFoundVarchar ,' null')
如果 @ loopCount = @ myDesiredInt
开始
set @myFoundVarchar = @ myVarchar
set @myFoundInt = @ myInt
end
set @ loopCount = @ loopCount + 1
fetch next 来自 myCursor into @ myInt , @ myVarChar
end
关闭 myCursor
deallocate myCursor
print @ myFoundVarchar
print @ myFoundInt
注意事项:
- 我正在使用@loopcount
来计算提取的行数从光标 - 当我找到我想要的行时,我只设置输出变量。
- 我在每个循环中无条件地增加@loccount
- 我在循环中无条件地获取光标的下一行
- 循环中那个冗长的打印语句只是为了演示正在发生的事情,即
1:text19:19:null:null
2:text18:18:null:null
3:text17:17:null:null
4:te xt16:16:null:null
5:text15:15:16:text16
6:text14:14:16:text16
7:text13:13:16:text16
8:text12:12:16:text16
9:text11:11:16:text16
10:text10:10:16:text16
11:text9:9:16:text16
12:text8:8:16:text16
13:text7:7:16:text16
14:text6:6:16:text16
15:text5:5:16:text16
16:text4:4:16:text16
17:text3:3:16:text16
18:text2:2:16:text16
19:text1:1:16 :text16注意 - 因为
请注意,光标直到结束 - 这是游标提取数据的一种非常低效的方式之一。
通过引入另一个变量decl,可以突破游标循环是 @ abortLoop int = 0,将
WHERE
更改为,而( @@ FETCH_STATUS = 0 和 @ abortLoop = 0 )并将新变量设置为另一个值找到所需的值
设置@myFoundVarchar = @myVarchar
设置@myFoundInt = @myInt
设置@abortLoop = 1
然后输出是
1 :text19: 19 : null : null
2 :text18: 18 : null : null
3 :text17: 17 : null : null
4 :text16: 16 : null : null
text16
16 跨度>
I want to find the 4-th order for each customer and his Title_order (ordering by date of order) between all of its orders. If they dont have orders or have less than 4 return NULL. It's restricted using Cursor. I have created this but returns me all the order.
I have the tables
customer with filds fname, lname,Id_customer
order with filds ID_order, date, title_order
ALTER function [dbo].[f4order](@id_customer int, @ID_order int)
returns varchar (255)
as begin
declare @row3 as int, @data as date, @4order as varchar(50)
DECLARE myCursor CURSOR FOR
select ID_order
from (select ID_order , ROW_NUMBER() over(order by DATE desc) as row from order
where Id_customer=@id_customer) as tmp
where row=4
open myCursor;
FETCH NEXT FROM myCursor INTO @row4
WHILE @@FETCH_STATUS = 0
begin
if (@row4= @ID_order)
begin
set @4order= (select number from order where @ID_order=ID_order)
end
else
set @4order ='null'
FETCH NEXT FROM myCursor INTO @row4;
end
CLOSE myCursor
DEALLOCATE myCursor
return @4order
end
;
don't know if could be done
Thanks in advance
Well I finally got your code to return the correct answer once I'd fixed all of the bugs...
ORDER
andDATE
are reserved words, so if you are going to use them as table or column names you must surround them with square brackets i.e.[order], [DATE]
. Better still, choose different names. You also did not declare@row4
.
In the code you have presented there is no need for a cursor at all because you have usedROW_NUMBER
meaning you can target the 4th row directly - which is essentially what you have done withwhere row=4
NOTE: It is just as well that the query forming the cursor returns only a single row as you have theFETCH NEXT
within anELSE
clause. If you are going to use a cursor then make sure you always fetch the next row otherwise you could end up in an infinite loop.
The following trivial example shows how to find the 4th row in a query using a cursor (CAVEAT - this is not a recommended approach and is used to demonstrate the cursor only)
I set up some sample data that contains an int with the numbers 1 to 19 inclusive and a varchar column that contains some text (the word 'text' followed by the same number as the id)
create table cursorExample ( id int identity(1,1), someData varchar(max) ) declare @i int = 1 while @i < 20 begin insert into cursorExample values ('text' + cast(@i as varchar)) set @i = @i + 1 end
Now imagine I want to find the 4th row from the end of that table. I.e. the 4th row of this queryselect id, someData from cursorExample order by id DESC
I can do that with the following sqldeclare @myInt int declare @myVarchar varchar(max) declare @myDesiredInt int = 4 declare @myFoundVarchar varchar(max) declare @myFoundInt int declare @loopCount int = 1 declare myCursor cursor for select id, someData from cursorExample order by id DESC open myCursor fetch next from myCursor into @myInt, @myVarChar while @@FETCH_STATUS = 0 begin print cast(@loopCount as varchar) + ' : ' + @myVarChar + ' : ' + cast(@myInt as varchar) + ' : ' + isnull(cast(@myFoundInt as varchar), 'null') + ' : ' + isnull(@myFoundVarchar,'null') if @loopCount = @myDesiredInt begin set @myFoundVarchar = @myVarchar set @myFoundInt = @myInt end set @loopCount = @loopCount + 1 fetch next from myCursor into @myInt, @myVarChar end close myCursor deallocate myCursor print @myFoundVarchar print @myFoundInt
Points to note:
- I'm using@loopcount
to count the rows fetched from the cursor - I only set the "output" variables when I find the row I want.
- I increment@loopcount
unconditionally within each loop
- I fetch the next row of the cursor unconditionally within the loop
- That long-winded print statement within the loop is just to demonstrate what is going on i.e.
1 : text19 : 19 : null : null 2 : text18 : 18 : null : null 3 : text17 : 17 : null : null 4 : text16 : 16 : null : null 5 : text15 : 15 : 16 : text16 6 : text14 : 14 : 16 : text16 7 : text13 : 13 : 16 : text16 8 : text12 : 12 : 16 : text16 9 : text11 : 11 : 16 : text16 10 : text10 : 10 : 16 : text16 11 : text9 : 9 : 16 : text16 12 : text8 : 8 : 16 : text16 13 : text7 : 7 : 16 : text16 14 : text6 : 6 : 16 : text16 15 : text5 : 5 : 16 : text16 16 : text4 : 4 : 16 : text16 17 : text3 : 3 : 16 : text16 18 : text2 : 2 : 16 : text16 19 : text1 : 1 : 16 : text16Note - because the
Notice that the cursor runs "until the end" - which is one of the reasons that cursors can be a very inefficient way to extract data.
It is possible to "break out" of the cursor loop by introducing another variabledeclare @abortLoop int = 0, change the
WHERE
to bewhile (@@FETCH_STATUS = 0 and @abortLoop = 0)and set the new variable to another value once the desired values are found
set @myFoundVarchar = @myVarchar set @myFoundInt = @myInt set @abortLoop = 1The output will then be
1 : text19 : 19 : null : null 2 : text18 : 18 : null : null 3 : text17 : 17 : null : null 4 : text16 : 16 : null : null text16 16
这篇关于如何用光标找到每个客户的第四个订单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!