求数据分组,明天再加100分

JiangHongTao 2008-01-27 11:07:01
定义一表,求数据分组
数据关系,根据第一条记录的字段b查询下一条记录,使得要查询的记录字段a等于b,
然后以新的b循环查找,这样就能构成一个数据环,得到数据环后输出该数据环。
根据@n的不同,输出的数据可以不同,但至少有三条记录。例子如下:
declare @t table(a int,b int)
declare @n int
set @n = 5
declare @i int
select @i = 1
while @i <=2*@n
begin
insert @t select @i,(2*@i-1)%(2*@n-1)
set @i = @i+1
end
update @t set b = 2*@n -1 where b = 0
update @t set b = 2*@n where a = 2*@n
select * from @t
/*例如
当@n = 4,原始数据
a b
----------- -----------
1 1
2 3
3 5
4 7
5 2
6 4
7 6
8 8
要求输出
id c
---- ------------
1 1
2 2,3,5
3 4,7,6
4 8,8
当@n = 5时,原始数据
a b
----------- -----------
1 1
2 3
3 5
4 7
5 9
6 2
7 4
8 6
9 8
10 10
要求输出
id c
---- ------------
1 1
2 2,3,5,9,8,6
3 4,7
4 10,10
*/
...全文
558 107 打赏 收藏 转发到动态 举报
写回复
用AI写文章
107 条回复
切换为时间正序
请发表友善的回复…
发表回复
JiangHongTao 2008-01-31
  • 打赏
  • 举报
回复
再挂3天,没有新方法就结贴。
playwarcraft 2008-01-29
  • 打赏
  • 举报
回复
蒼天啊,我是真的看不懂。。。
給say下嘛
昵称被占用了 2008-01-29
  • 打赏
  • 举报
回复
...

呵呵,这数要是能找到更简单的规律,速度才能提高

playwarcraft 2008-01-29
  • 打赏
  • 举报
回复
唉。。。看不懂你們在弄什么了。。。
誰來抽空say say,為什么@n=5,就出來1,2,4,10 ?
JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
比如我的函数修改如下:注意需要增加条件语句对应的ELSE计数器.
create  function f_geth(@n int)
returns varchar(8000)
as
begin
declare @t table(a int)
declare @s varchar(8000)
declare @cc int --定义计数器变量
set @cc = 0 --初始化计数器

declare @i int,@id int,@c int
set @s = ''
set @i = 2
set @c = 2*@n -1
while @i <=@c
begin
if not exists(select 1 from @t where a= @i)
begin
set @s = @s +','+rtrim(@i)
delete @t where a < @i
insert @t select @i
set @id = (2*@i-1)%@c
if @id = 0 set @id = @c
while @i <> @id
begin
set @cc = @cc +1 --最内层计数器加1
insert @t select @id
set @id = (2*@id-1)%@c
if @id = 0 set @id = @c
end
end
else --计数器新增的。
set @cc = @cc + 1 --虽然在正常的代码中不需要,但计数器需要计数。
set @i = @i+2
end
return stuff(@s,1,1,'')
end
JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
最简单的测试方式就是在你的函数的最内层循环增加一个计数器,当计数器的数值与@n成线性关系就可以了,当然由于数据量太大,不能用表计算。
JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
感谢各位,特别感谢dobear_0922,
他是第一个不用表就计算出结果的,应该是明白了我的数据关系。
不过用的循环嵌套过多,当我的@n很大的时候,性能下降急剧,

现在软件性能需求中的要求是执行时间与@n成线性关系。

即 执行时间 = a×@n(a为一个常数或接近常数,至少与@n无关)

-狙击手- 2008-01-29
  • 打赏
  • 举报
回复
哦,嘿嘿
-狙击手- 2008-01-29
  • 打赏
  • 举报
回复
楼主的这个函数怎么当n = 5 时结果 是2,4
不是1,2,4,10 呀
JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
我去掉了固定的第一项和最后一项。
JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
create  function f_geth(@n int)
returns varchar(8000)
as
begin
declare @t table(a int)
declare @s varchar(8000)
declare @i int,@id int,@c int
set @s = ''
set @i = 2
set @c = 2*@n -1
while @i <=@c
begin
if not exists(select 1 from @t where a= @i)
begin
set @s = @s +','+rtrim(@i)
delete @t where a < @i
insert @t select @i
set @id = (2*@i-1)%@c
if @id = 0 set @id = @c
while @i <> @id
begin
insert @t select @id
set @id = (2*@id-1)%@c
if @id = 0 set @id = @c
end
end
set @i = @i+2
end
return stuff(@s,1,1,'')
end
GO


上面的执行结果就是正确结果,参数为n,总共2n项目数据。
其实本题就是将1...2n的自然数进行环分组。目前由于对分组计算的循环(有大量数据(约10亿)需要分析,并根据不同的规则组合生成了分类数据,每类数据均为2n个,n不确定,对每类数据需要函数给出的结果进行后续操作,我这里给出的是组合生成数据的下标)调用巨大,所以对分组的时间要求极高。
昵称被占用了 2008-01-29
  • 打赏
  • 举报
回复
恩,我也发现是这个问题了
测试了下,还是66楼的速度最快

我刚才想改成双向寻找的,因为正推的算法是
case when @i >@n then (@i-@n)*2 else 2*@i-1 end
还可以反推,算法是
case when @i % 2 =0 then @n+@i/2 else (@i+1)/2 end

但是改了下,速度没有提高,这个思路你可以考虑下

dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
计算1000万用了5分38秒,看来还有很大的提升空间:
1,2,4,20000000
dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
改了后的结果:
/*4                    5                    6                    7
-------------------- -------------------- -------------------- --------------------
1,2,4,8 1,2,4,10 1,2,12 1,2,14

(1 row(s) affected)*/
dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
create function fn_GetNums(@nMax int)
returns varchar(max) as
begin
declare @i int, @sql varchar(max)
select @i = 2, @sql='1'
while @i<=@nMax
begin
declare @ii int, @ntimes int
select @ii=@i, @ntimes=1
while @ii<=@nMax
set @ii=2*@ii-1
while @ntimes<=2*@nMax
begin
set @ii=2*(@ii-@nMax)
if @ii>@i
while @ii<=@nMax
set @ii=2*@ii-1
else if @ii=@i
begin
set @sql=@sql+','+rtrim(@i)
break
end
else if @ii%2=0
break
set @ntimes=@ntimes+1
end
set @i=@i+2
end
return @sql+','+rtrim(2*@nMax) --63楼的这个地方错了,忘了改了,不好意思
end

go
--print dbo.fn_GetNums(1000)
--print dbo.fn_GetNums(1001)
--print dbo.fn_GetNums(10000)
--print dbo.fn_GetNums(100000)
print dbo.fn_GetNums(1000000)

drop function dbo.fn_GetNums
昵称被占用了 2008-01-29
  • 打赏
  • 举报
回复
dobear_0922 :
63楼的执行结果:

select cast(dbo.fn_GetNums(4) as varchar(20)) as [4]
,cast(dbo.fn_GetNums(5) as varchar(20)) as [5]
,cast(dbo.fn_GetNums(6) as varchar(20)) as [6]
,cast(dbo.fn_GetNums(7) as varchar(20)) as [7]

--结果
4 5 6 7
-------------------- -------------------- -------------------- --------------------
1,2,4,6 1,2,4,6 1,2,8 1,2,8

(所影响的行数为 1 行)


好像结果有问题,问题好像是
            else if @ii%2=0
break

错误造成提前退出循环,因为思路不同,不能确定



ps:我觉得搂主应该负责验证结果,并及时贴出来,因为只有搂主最了解答案正确与否,否则太浪费时间,不利于找出好的答案

JiangHongTao 2008-01-29
  • 打赏
  • 举报
回复
有没有可能不通过循环或者通过一次循环就输出结果。
dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
到此为止了,接下来我会继续关注,看看有没有人有更好的解决方案
dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
想要最快的速度,恐怕只能求助于数学牛人了,这些环应该是有规律的,,,

根据我的分析:
对于一个有2n个元素数列: 1,3,5,...,2-1,2,4,6,...,2n
数列中的每个元素必然在一个环(1~1, a~b~...~d~a, 2n~2n)上,且除两端的2个环外,每个环的最小元素均为不大于n的偶数。
dobear_0922 2008-01-29
  • 打赏
  • 举报
回复
楼主的这个速度还可以呀,不是很慢呀

---------
和我的一样,100万用14秒
加载更多回复(87)
数据数据析-RFM模型⽤户析 模型⽤户析 RFM模型 根据美国数据库营销研究所Arthur Hughes的研究,客户数据库中有3个神奇的要素,这3个要素构成了数据析最好的指标: 最近⼀次消费 (Recency) 消费频率 (Frequency) 消费⾦额 (Monetary) 上⾯的三个标签通过字⾯意思⽐较好理解,顾名思义RFM模型中的,R=Recency,F=Frequency,M=Monetary RFM模型客户细 1.数据筛选 为了得到客户最近⼀次消费(Recency)、消费频率(Frequency)、消费⾦额(Monetary)这三个指标的数值进⾏筛选(以下为⼀个⽰例)。 消费(Recency)——最近⼀次会员来店铺购买的时间 A、⼀周以前 B、2周以前 C、3周以前 D、⼀个⽉前 消费频率(Frequency)——⼀年内在店铺购买的次数 A、1次 B、1-3次 C、3-5次 D、5次以上 对于消费⾦额(Monetary)——单次消费⾦额 A、50元以下 B、50-150元 C、150-300元 D、300元以上 2.数据处理 处理步骤如下: 将所有客户按照Recency的值,由⼩到⼤排列,以50%为⼀群,依次给予2,1。 再将所有客⼾按照Frequency的值,由⼤到⼩排列;以50%为⼀群,依序给予2,1。 最后将所有客⼾按照Monetary的值,由⼤到⼩排列;以50%为⼀群,依序给予2,1。 整合得到8种组合: 2-2-2:⾼价值客户; 2-1-2:重点发展客户 1-2-2:重点保持客户; 1-1-2:重点挽留客户; 1-1-1:⽆价值客户; 其余三种组合均属于⼀般客户。 现在我们来简单归纳⼀下,RFM模型中,我们重点研究的就是以上8种⽤户(⽤排列组合2*2*2=8种,很好理解)⾥⾯的有明显偏向的5种⽤户. 前⾯的4种⽤户,⼊选研究对象,总概括的就是愿意掏钱的客户. 这下就很好记了,RFM⾥⾯的M已经确定了,要选掏钱的,R,F各有两种选择,也就是总共4种类型 然后再按R来,打⾼的先排 2 2 2 这种客户"最近购买(r),⽽且经常购买(F),每次花钱的⾦额还挺⼤(M) 毫⽆疑问这个客户是⾼价值的 2 1 2 此客户最近购买,买的次数不多,但每次花费的⾦额⽐较⼤;那么遇到这种客户,证明他对特定品牌产品感兴趣,要做的是怎么让他经常来 买. 所以这种客户不难理解是应该重点发展的 1 2 2 此客户可能不是⼀直关注产品,但是买的次数⽐较频繁,每次花费的⾦额也挺⼤. 理解:证明这个客户是对产品的需量⽐较⼤,也舍得掏钱,对品牌不是很关注的,也许今天到A品牌商家购买的,明天就到B品牌商家购买 去了.因此我们要做的是,要让客户保留对我们品牌产品的兴趣. 1 1 2 此客户⽐较明显就是那种⽐较懒惰型的客户,要⽤到的时候再买,⽽且⼀次性买⽐较多,平时就很少关注和购买了.对于这种客户,你不知 道他下⼀次购买的还是不是本公司品牌的产品,可能需要在他购买⼀段时间后提醒他我们产品有优惠活动,来提起他的购买欲望.因此属于需要 挽留型的客户 1 1 1 就不多说了,是临时过客 其他的客户没有明显的特征,主要是不怎么掏钱,是薅⽺⽑型的,你再怎么打主意都从他⾝上挣不到多少钱的,就归为⼀般客户. 理解完后,就根据打,把所有客户类好,然后提取出来我们重点研究的这⼏种客户来做相应的措施; 2 2 2⾼价值客户,基本上不⽤太担⼼,他会⾃⼰来购买 2 1 2 重点发展型的客户 想办法加⼤他的购买频率 1 2 2重点保持型客户 让他保持对我们品牌产品的兴趣 1 1 2重点挽留客户 发⼀些我们品牌的信息给他,等他想起来要购买类似产品的时候,第⼀时间想到的是我们品牌 1 1 1 ⽆价值的客户 不⽤花精⼒去跟进这种类型的客户,投⼊和产出⽐不值得.

22,206

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 疑难问题
社区管理员
  • 疑难问题社区
  • 尘觉
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧