问一下搂住:
例要求列1 P出现3次,b出现3次,l出现3次,列2 --i出现3次,ao 出现2次,an 出现4次这样的条件来取数据。
是在原有的数据中找到满足条件的记录还是把列1满足条件的记录和列2满足条件的记录组合到一起生成一个新的结果集?
例要求列1 P出现3次,b出现3次,l出现3次,列2 --i出现3次,ao 出现2次,an 出现4次这样的条件来取数据。
是在原有的数据中找到满足条件的记录还是把列1满足条件的记录和列2满足条件的记录组合到一起生成一个新的结果集?
处理思想:由外部条件组合成一个结果集,与原结果集联合查询。
说明:外部条件列1和列2条件的行数应该相同。并返回这个行数的结果集。
sql中没有现成的关于一个字符串的全部排列组合的函数,所以由外部程序处理传入
(我试了一下,不是马上能在sql中解决这个算法的,幸好外部程序的算法比较多,可以传入)
部分变量的定义的长度需要统一和修改。
实际也不知道这个能否满足搂住的要求。
你可以在你的数据上试试,前提是你有的外部程序有个能得出某个字符串的全部排列组合的算法。
*/
--辅助函数:将字符串变为表
CREATE FUNCTION dbo.fnt_SplitString
(
@string varchar(8000), --以分隔符为结尾。
@split_flag char(1)
)
RETURNS @tbl table
( item_id int identity(1,1),
item varchar(100)
)
asbegin
if len(isnull(@split_flag,''))=0
select @split_flag=@split_flag
if len(isnull(@string,''))=0
select @string='0'+@split_flag
if right(@string,1)<>@split_flag
select @string=@string+@split_flag
declare @var_value varchar(100) --分隔出的项值
declare @str_len integer --字符串长度
declare @str_pos integer --‘,’在字符串中的起始位置 select @str_len=len(@string)
select @str_pos=charindex(@split_flag,@string)
while @str_pos >0
begin
select @var_value=substring(@string,1,@str_pos -1)
if @var_value<>''
insert into @tbl(item) values(@var_value)
select @string=substring(@string,@str_pos+1,@str_len - @str_pos)
select @str_len=len(@string)
select @str_pos=charindex(@split_flag,@string)
end return
end
go
--主表数据
create table #t (col1 varchar(10),col2 varchar(10),col3 varchar(50))
insert into #t
select 'p','i','pi'
union all select 'b','ao','bao'
union all select 'l','an','lan'
union all select 'l','i','li'
union all select 'p','an','pan'
union all select 'p','ao','pao'
union all select 'b','i','bi'
union all select 'l','an','lan'
union all select 'b','an','ban'
drop procedure getresult
create procedure getresult(@col1_condition varchar(200),--列1的条件,使用值,数目;....格式传递
@col2_condition varchar(200),--列2的条件,使用值,数目;....格式传递
@pstr varchar(8000)) --列2的全部排列组合,如条件:列2 a出现2次,c出现1次,则应该是a,a,c字符串的所有排列组合。
as
begin
declare @sqlstr varchar(1000)
select @sqlstr=''
select @sqlstr=@sqlstr+replicate('union all select '''+left(item,charindex('_',item)-1)+''',''0'' ',convert(int,right(item,len(item)-charindex('_',item))))
from dbo.fnt_splitstring(@col1_condition,',')
select @sqlstr='insert into #condition(col1value,flag) '+stuff(@sqlstr,1,10,'')--辅助表1,获得每笔内容。如P出现两次,则为两条记录。
--这里是:列一:p 出现两次,b出现一次;l 出现一次;列二:i出现1次,ao出现1次,an出现两次。
create table #condition(id int identity(1,1),col1value varchar(10),flag char(1))
exec(@sqlstr) select @sqlstr=''
select @sqlstr=@sqlstr+replicate('union all select '''+left(item,charindex('_',item)-1)+''',''1'' ',convert(int,right(item,len(item)-charindex('_',item))))
from dbo.fnt_splitstring(@col2_condition,',')
select @sqlstr='insert into #condition(col1value,flag) '+stuff(@sqlstr,1,10,'') exec(@sqlstr)
/*
select 'p','0'
union all select 'p','0'
union all select 'b','0'
union all select 'l','0'
union all select 'i','1'
union all select 'ao','1'
union all select 'an','1'
union all select 'an','1'
*/
--外部实现的列2要出现的字母的排列组合。
--declare @pstr varchar(8000)
-------外部排列组合的程序比较多,但是我这里也没有现成的,所以手工列出来几个,以做测试。如谁有sql中的字符串排列组合的算法,可以提供一下。
--select @pstr='i,ao,an,an;i,an,ao,an;i,an,an,ao;ao,i,an,an;ao,an,i,an;ao,an,an,i;an,ao,i,an;an,ao,an,i;an,an,i,ao;an,an,ao,i;'
--辅助表2记录所有的排列组合
create table #p(id int identity(1,1),sortstr varchar(100))
insert into #p(sortstr)
select item from dbo.fnt_splitstring(@pstr,';')
--辅助表3将某个排列组合的字符串序列化为行数据。
create table #s(id int identity(1,1),colvalue varchar(20))
--循环找符合的记录
declare @outrowcount int,@i int,@allcount int,@tempcount int
select @outrowcount=count(1) from #condition where flag='0' --要输出的总行数
select @allcount=count(1) from #p
select @i=1
while @i<=@allcount
begin
--获取排序的字符串
declare @str varchar(50)
select @str=sortstr from #p where id=@i
truncate table #s
--转化为表
insert into #s(colvalue)
select item from dbo.fnt_splitstring(@str,',')
--获得结果的行数
select @tempcount=count(1)
from #t a,
(select id,col1value from #condition where flag='0') b,
(select id,colvalue from #s) c
where a.col1=b.col1value and a.col2=c.colvalue and b.id=c.id
if @tempcount=@outrowcount
break
select @i=@i+1
end
if @tempcount=@outrowcount
select a.*
from #t a,
(select id,col1value from #condition where flag='0') b,
(select id,colvalue from #s) c
where a.col1=b.col1value and a.col2=c.colvalue and b.id=c.id
else
print 'no'
drop table #condition
drop table #p
drop table #s
end--调用测试:
declare @1 varchar(200),@2 varchar(200),@3 varchar(8000)
select @1='p_2,b_1,l_1'
select @2='i_1,ao_1,an_2'
select @3='i,ao,an,an;i,an,ao,an;i,an,an,ao;ao,i,an,an;ao,an,i,an;ao,an,an,i;an,ao,i,an;an,ao,an,i;an,an,i,ao;an,an,ao,i;'
exec getresult @1,@2,@3
--结果
/*
col1 col2 col3
----------------------
l i li
p an pan
p ao pao
b an ban*/
drop procedure getresult
了。
列2(韵母) --an出现5次,ao 出现2次,ang 出现2次这样的条件来取数据也就是:
列1(声母): w(3), sh(1), d(5)
列2(韵母): an(5), ao(2), ang(2)问题是:在这个结果集中可以不可出其他值,如:列1(声母)出现x... 列2(韵母)出现e....?
问题二:列1 的声母数目、列2的韵母数目 是不是就是3个,会不会多或者少?这个问题可以转化成:
在源集合中,组合出现的统计数T(w_an, w_ao, w_ang, sh_an, sh_ao, sh_ang, d_an, d_ao, d_ang ),
独立出现的统计数T(w, sh, d, an ,ao, ang) 如果目标集存在,不是取自 组合集, 就是取自 独立集.
分别为:
Z_w_an, Z_w_ao, Z_w_ang, Z_sh_an, Z_sh_ao, Z_sh_ang, Z_d_an, Z_d_ao, Z_d_ang
D_w, D_sh, D_d, D_an ,D_ao, D_ang 应满足等式:
Z_w_an + Z_w_ao + Z_w_ang + D_w = w(3)
Z_sh_an+ Z_sh_ao + Z_sh_ang + D_sh = sh(1)
Z_d_an + Z_d_ao + Z_d_ang + D_d = w(3)
Z_w_an + Z_sh_an+ Z_d_an + D_an = an(5)
Z_w_ao + Z_sh_ao + Z_d_ao + D_ao = ao(2)
Z_w_ang + Z_sh_ang +Z_d_ang + D_ang = ang(2) 和不等式:
Z_w_an < T_w_an
Z_w_ao < T_w_ao
Z_w_ang < T_w_ang
Z_sh_an < T_sh_an
Z_sh_ao < T_sh_ao
Z_sh_ang< T_sh_ang
Z_d_an < T_d_an
Z_d_ao < T_d_ao
Z_d_ang < T_d_ang
D_w < T_w
D_sh < T_sh
D_d < T_d
D_an < T_an
D_ao < T_ao
D_ang < T_ang 在简化公式后在求数。这个例子中组合统计数应为0,1
你贴的代码,滚了五下滚轮才滚完。
楼主,不给他全分,就不厚道哦。
而我又感觉自己理解了有点他的意思(也不知道对不),
所以就耗费了半天的时间弄了一下,倒是排列组合难住了。没想到好的方法。
楼上有空帮忙写个sql的某个字符串的排列组合的算法。
-- 感谢 rivery 给于的灵感,用以下方法返回所有的组合,大家互相探讨if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[uf_BitNumber]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[uf_BitNumber]
GO
create function uf_BitNumber (@in bigint)
returns int as
begin
declare @i int, @n bigint
set @i = 0
set @n = @in while @n >0
begin
if @n % 2 >0
begin
set @i = @i +1
end
set @n = @n /2 -- FLOOR
end
return @i
end
GO
--主表数据
declare @tsrc table (id int IDENTITY(0,1) PRIMARY KEY, c1 varchar(10),c2 varchar(10),c3 varchar(50))
insert into @tsrc (c1,c2,c3)
select 'p','i' ,'pi'
union all select 'b','ao','bao'
union all select 'l','an','lan'
union all select 'l','i' ,'li'
union all select 'p','an','pan'
union all select 'p','ao','pao'
union all select 'b','i' ,'bi'
union all select 'l','an','lan'
union all select 'b','an','ban'declare @c1str as varchar(400), @c2str as varchar(400), @sqlstr as varchar(400)
set @c1str ='p_2,b_1,l_1'
set @c2str ='i_1,ao_1,an_2'
if exists( select * from tempdb..sysobjects where id = OBJECT_ID('tempdb..#tc1') and type='U' ) drop table #tc1
if exists( select * from tempdb..sysobjects where id = OBJECT_ID('tempdb..#tc2') and type='U' ) drop table #tc2
create table #tc1 ( i varchar(40), n int, h bigint)
create table #tc2 ( i varchar(40), n int, h bigint)declare @tgrp table (id int IDENTITY(0,1) PRIMARY KEY,id0 int, c1 varchar(10),c2 varchar(10)/*, mcnt int*/, h bigint)
declare @tout table (id int IDENTITY(0,1) PRIMARY KEY,id0 int, c1 varchar(10),c2 varchar(10)/*, mcnt int*/, h bigint)set @sqlstr = 'select ''' +replace(replace(@c1str,',',' union all select ''') ,'_',''',')
insert into #tc1(i,n) exec ( @sqlstr )
set @sqlstr = 'select ''' +replace(replace(@c2str,',',' union all select ''') ,'_',''',')
insert into #tc2(i,n) exec ( @sqlstr )insert into @tgrp (c1, c2, id0 )
select c1,c2, id from @tsrc,(
select a.i i1, b.i i2 from #tc1 a, #tc2 b
) x
where x.i1 = c1 and x.i2 = c2
update @tgrp set h=power(2,id)update #tc1 set h=x.h from (
select c1, sum(h) h from @tgrp group by c1
) x, #tc1 a
where x.c1 = a.iupdate #tc2 set h=x.h from (
select c2, sum(h) h from @tgrp group by c2
) x, #tc2 a
where x.c2 = a.i
declare @max as int, @max2 as int, @i as int
select @max= count(*) from @tgrp
set @max2 = power(2, @max )-1
while @max2 >0
begin
if not exists( select * from #tc1 where dbo.uf_BitNumber( h & @max2) <> n )
and not exists( select * from #tc2 where dbo.uf_BitNumber( h & @max2) <> n )
begin
insert into @tout(c1,c2,h, id0 )
select c1,c2, @max2,id0 from @tgrp where @max2 & h >0
end
set @max2 = @max2 -1
endselect count(DISTINCT h) from @tout
select * from @tout order by h, id0drop table #tc1
drop table #tc2
/*
这个方法使用bit 代表各种组合,返回所有的可能的组合.限制-- (声母(这里是3) * 韵母(这里是3)) (即@tgrp记录数) < 62(整数位数)如果需要突破这限制,可以用varchar/ varbinary/ 多个bigint 代替 bigint ,并替换以下方法:
Power(移位), Sum(|或,聚合函数) , &(与), uf_BitNumber(1的计数), @max2 如(varchar(4000)):
set @max2a = REPLICATE('1',@max)
set @max2b = REPLICATE('0',@max)
set @max2 = @max2a
移位: STUFF( @max2b, id,1,'1')
或,聚合: bintochar(sum(chartobin()): varchar bintochar(dec(30)), dec(30) chartobin(varchar) ........
与: charAND(varchar,varchar)......
1的计数: len( REPLACE(charAND( h, @max2), '0','')*//*
结果:(7组)
id id0 c1 c2 h
_______________________________________
24 0 p i 75
26 1 b ao 75
27 2 l an 75
25 4 p an 75
23 2 l an 86
20 4 p an 86
21 5 p ao 86
22 6 b i 86
16 0 p i 101
19 2 l an 101
17 5 p ao 101
18 8 b an 101
15 3 l i 166
12 4 p an 166
13 5 p ao 166
14 8 b an 166
8 0 p i 267
10 1 b ao 267
9 4 p an 267
11 7 l an 267
4 4 p an 278
5 5 p ao 278
6 6 b i 278
7 7 l an 278
0 0 p i 293
1 5 p ao 293
3 7 l an 293
2 8 b an 293
*/
sekect distinct 列1,列2,列3 into NewTable from YourTable
先产生一个可能的组合表.3.因为以上原因,传入的条件是否有所限制??4.你的表二万多记录,是所有汉字都存在? 还是其它什么? 表述不够细.给出真实的表结构和内容.和你如此查询的真实目的与用处. 这样大家也好看看.
答:ID 主键 ,结果抽出是根据条件的提取,表的数据是这样的
id 列1 列2 列3 列4
1 p i pi
2 b ao bao
3 l an lan
4 l i li
5 p an pan
6 p ao pao
7 b i bi
8 l an lan
9 b an ban
10 zh ai zhai
11 b ing bing
12 p en pen
等数据
id 列1 列2 列3 列4---》说明如下id 主键自动ID
列1 是 声母
列2 是 韵母
列3 是 该词或者词组的拼音
列4 是 该词或者词组,即中文汉字 要求是这样,现在要出一道题目共100个字,要求含声母b,l,zh与韵母ao,ban,en提取数据(这里只说明意思列出这点声母与韵母),
但是在提取100个字中,要求含声母b出现50次,l出现20次,zh出现32次 韵母ao出现12次,ban出现38次,en出现50次。
也就是,按要求提取相应的数据来。2.随机组合容易.但不存在的组合,你得事先剔除.比如: g k h 和 ian 组合就不存在.是前台去除还是后台处理?
答:实际上不是随机组合,因为在我选择的声母与韵母范围来提取数据,不可以组合,可以控制,有一定规律,可以在过滤掉的。后台这里出题提供条件,在前台每一人点后随机出来数据,在数据上区别是同音不同字,但是不足要求提取的数量必须提示 。 3.因为以上原因,传入的条件是否有所限制??
答:传入 是对应声母与韵母以及出现次数和总取的总字数[也就是实际声母与韵母各自的总数,例要取100个字,那么声母100与韵母100]
4.你的表二万多记录,是所有汉字都存在? 还是其它什么? 表述不够细.
答:是我们试题需要的相关字。相关看上述描述
select @s1=replicate('p,',50)+replicate('l,',18)+replicate('zh,',32),
@s2=replicate('ao,',32)+replicate('an,',18)+replicate('en,',50)select @s1=left(@s1,len(@s1)-1),@s2=left(@s2,len(@s2)-1)select @s1='select '''+replace(@s1,',',''' union all select ''')+'''',
@s2='select '''+replace(@s2,',',''' union all select ''')+''''create table #t1(id int identity,s varchar(10))create table #t2(s varchar(10))insert #t1 exec(@s1)insert #t2 exec(@s2)--2.用order by newid()把韵母随机打乱
declare @a table(id int identity,s varchar(10))
insert @a(s) select s from #t2 order by newID() select A.s as 声母,B,s as 韵母 from #t1 A,@a B where A.id=B.id
--@b 存随机抽出的ID
declare @b(id int)declare @声母 varchar(10),@韵母 varchar(10)--用游标100次循环随机抽出符合条件不重复的ID
declare c cursor for
select A.s,B,s from #t1 A,@a B where A.id=B.idOPEN cFETCH NEXT FROM authors_cursor
INTO @声母,@韵母WHILE @@FETCH_STATUS = 0
begininsert @b
select id from 源表
where 列1=@声母 and 列1=@韵母
and id not in (select id from @b)
FETCH NEXT FROM authors_cursor
INTO @声母,@韵母end
drop table #t1,#t2
--最后跟据得到的ID从源表中取出结果.
select * from 源表 where id in (select id from 源表 )
CLOSE c
DEALLOCATE c就当所有组合都存在.都可以找出记录.如果组合不存在,
在组合结果时要先调整.比如:
调束措失:
select 列1,列2,count(*) 存在记录数 into newTable from 源表 group by 列1,列2
这样你在传入条件时先做些判断,适当调整随机组合的声母韵母结果.然后再随机抽取.
WHILE @@FETCH_STATUS = 0
begininsert @b
select top 1 id from 源表
where 列1=@声母 and 列1=@韵母
and id not in (select id from @b)
order by newid()FETCH NEXT FROM authors_cursor
INTO @声母,@韵母end
select @s1=replicate('p,',50)+replicate('l,',18)+replicate('zh,',32),
@s2=replicate('ao,',32)+replicate('an,',18)+replicate('en,',50)select @s1=left(@s1,len(@s1)-1),@s2=left(@s2,len(@s2)-1)select @s1='select '''+replace(@s1,',',''' union all select ''')+'''',
@s2='select '''+replace(@s2,',',''' union all select ''')+''''create table #t1(id int identity,s varchar(10))create table #t2(s varchar(10))insert #t1 exec(@s1)insert #t2 exec(@s2)--2.用order by newid()把韵母随机打乱
declare @a table(id int identity,s varchar(10))
insert @a(s) select s from #t2 order by newID() select A.s as 声母,B,s as 韵母 from #t1 A,@a B where A.id=B.id
--@b 存随机抽出的ID
declare @b(id int)declare @声母 varchar(10),@韵母 varchar(10)--用游标100次循环随机抽出符合条件不重复的ID
declare c cursor for
select A.s,B,s from #t1 A,@a B where A.id=B.idOPEN cFETCH NEXT FROM authors_cursor
INTO @声母,@韵母WHILE @@FETCH_STATUS = 0
begininsert @b
select top 1 id from 源表
where 列1=@声母 and 列1=@韵母
and id not in (select id from @b)
order by newid()FETCH NEXT FROM authors_cursor
INTO @声母,@韵母end
drop table #t1,#t2
--最后跟据得到的ID从源表中取出结果.
--select * from 源表 where id in (select id from 源表 )select * from 源表 where id in (select id from @b)---这儿改一下.
“--用游标100次循环随机抽出符合条件不重复的ID
declare c cursor for
select A.s,B,s from #t1 A,@a B where A.id=B.id
”
这样撞大运,成功概率不知怎样
是的.错了
declare c cursor for
select A.s,B,s from #t1 A,@a B where A.id=B.id
这样撞大运,成功概率不知怎样
"---你的理解可能成问题,到了这就不是"撞大运"了,这是有结果后,再从库中相同声韵中随机抽出一条.
--至于根本就不存在100条记录,那还何谈随机可言?最重要应该是:记录分布不均,我前面已经说过了,
select 列1,列2,count(*) 存在记录数 into newTable from 源表 group by 列1,列2组合记录时应该根据上面语句分析,再生成:
select A.s,B,s from #t1 A,@a B where A.id=B.id 结果集.
” 这个“结果”,并没有先得到源表的验证 只有满足以下条件,才有结果:
if not exists ( select * from (
select s1,s2, count(*) cnt from (
select A.s s1,B.s s2 from #t1 A,@a B where A.id=B.id
) group by s1, s2
) r
where cnt> (
select count(*) from 源表 b where b.列1 = r.s1 and b.列2= r.s2
)
-- ok再问搂主!!!!!!!“在提取100个字中,要求含声母b出现50次,l出现20次,zh出现32次 韵母ao出现12次,ban出现38次,en出现50次”:如果只有 b,l,zh; ao,ban,en组合怎么也得不到100个汉字,是不是有其他字母,只是不计数??还是不是因为包含多音字。还有:声母/韵母个数(不包含重复值)最多会有多少?
insert into @t(s1,s2,cnt)
select 列1,列2,count(*) from 源表 group by 列1,列2if not exists ( select * from (
select s1,s2, count(*) cnt from (
select A.s s1,B.s s2 from #t1 A,@a B where A.id=B.id
) group by s1, s2
) r
where cnt> isnull( (
select cnt from @t b where b.s1 = r.s1 and b.s2= r.s2
), 0)
)
-- ok
--“在提取100个字中,要求含声母b出现50次,l出现20次,zh出现32次 韵母ao出现12次,ban出现38次,en出现50次”:如果只有 b,l,zh; ao,ban,en组合怎么也得不到100个汉字,是不是有其他字母,只是不计数??
\\般来说在老师出题目的时候他回作细小的估计,基本是可以组合出个数,以上是我写的例数量,在这几个里是不可能.
--还是不是因为包含多音字。
\\是的
insert into @t(s1,s2,cnt)
select s1,s2, (
select count(*) from 源表 b where b.列1 = r.s1 and b.列2= r.s2
) cnt from (
select distinct A.s s1,B.s s2 from #t1 A,#t2 B where A.id=B.id
)
if not exists ( select * from (
select s1,s2, count(*) cnt from (
select A.s s1,B.s s2 from #t1 A,@a B where A.id=B.id
) group by s1, s2
) r , @t b
where b.s1 = r.s1 and b.s2= r.s2 and r.cnt> b.cnt
)
-- ok
declare @num int
set @num=50 --总记录数select @s1=replicate('d,',15)+replicate('f,',13)+replicate('b,',12),
@s2=replicate('an,',12)+replicate('ang,',13)+replicate('ao,',15)select @s1=left(@s1,len(@s1)-1),@s2=left(@s2,len(@s2)-1)select @s1='select '''+replace(@s1,',',''' union all select ''')+''''
,@s2='select '''+replace(@s2,',',''' union all select ''')+''''create table #t1(id int identity,s1 varchar(10),s2 varchar(10))create table #t2(id int identity,s varchar(10))insert #t1(s1) exec(@s1)insert #t2(s) exec(@s2)select voice0 as sm,rhyme0 as ym,count(*) as num into #t_num from T_SyllableData
group by voice0,rhyme0
order by voice0,rhyme0
declare @id1 int,@s varchar(10),@id2 int
set @id1=1
while @id1<=@num
begin
update A set @s=s2=(select top 1 s from #t2 B where (select num from #t_num where sm=A.s1 and ym=B.s)-(select count(*) from #t1 where s2=B.s)>0 order by newid())
from #t1 A where id=@id1
select @id2=(select top 1 id from #t2 where s=@s)
delete #t2 where id=@id2
select @id1=@id1+1,@id2=0,@s=''
endset @id1=1
declare @b table(id int)
while @id1<=@num
begin
insert @b
select top 1 SDid from T_SyllableData A,#t1 B
where voice0=B.s1
and rhyme0=B.s2
and B.id=@id1
and SDid not in (select id from @b)
order by newid()
set @id1=@id1+1
endselect * from T_SyllableData where SDid in (select id from @b)
order by voice0,rhyme0
--select * from #t2drop table #t1,#t_num,#t2
set @num=40 --总记录数--从源表中统计出各种组合的记录数.
select voice0 as sm,rhyme0 as ym,count(*) as num into #t_num from T_SyllableData
group by voice0,rhyme0
order by voice0,rhyme0--往声母表中填韵母,并且填一删一个,确保韵母总数正确,
--且同时判断这种填入组合是否在源表中存在,且总抽取数不超过源表中的组合数.
declare @id1 int,@s varchar(10),@id2 int
set @id1=1
while @id1<=@num
begin
update A set @s=s2=(select top 1 s from #t2 B where (select num from #t_num where sm=A.s1 and ym=B.s)-(select count(*) from #t1 where s2=B.s)>0 order by newid())
from #t1 A where id=@id1
select @id2=(select top 1 id from #t2 where s=@s)
delete #t2 where id=@id2
select @id1=@id1+1,@id2=0,@s=''
end
Sfid numeric identity,--key -----可要可不要!
SDid numeric null,--key
wstid int null,--类型ID
idorder int null,--词组的前后序号
voice varchar(50) null,--声母
rhyme varchar(50) null,--韵母日常书写
rhymefact varchar(50) null,--标准韵母
expression varchar(50) null--声调 1,2 3,4
)--在sdid,idorder上建联合主键,这种表没有索引和主键是不可思异的
create clustered index CluInd_Syl on T_SyllableFrom(sdid,idorder)
--从原表插入数据
insert INTO T_SyllableFrom
SELECT SDid,wstid,idorder=1,voice0 as voice ,rhyme0 as rhyme,rhyme00 as rhymefact,expression0 as expression from T_SyllableData
where voice0 is not null
union all
SELECT SDid,wstid,idorder=2,voice1 as voice ,rhyme1 as rhyme,rhyme01 as rhymefact,expression1 as expression from T_SyllableData
where voice1 is not null
union all
SELECT SDid,wstid,idorder=3,voice1 as voice ,rhyme2 as rhyme,rhyme02 as rhymefact,expression2 as expression from T_SyllableData
where voice2 is not null
union all
SELECT SDid,wstid,idorder=4,voice1 as voice ,rhyme3 as rhyme,rhyme03 as rhymefact,expression3 as expression from T_SyllableData
where voice3 is not null
这样表修改后,可扩展性大大增强.你原来的表只能固定最多四字词.这样一改随意性就强了.
原表如果碰到"一夫挡关,万夫莫开" 或 "不管三七二十一" 就得改表结构,这是表设计中最忌讳的.
declare @num int
set @num=100 --总记录数select @s1=replicate('d,',45)+replicate('f,',33)+replicate('b,',32),
@s2=replicate('an,',32)+replicate('ang,',33)+replicate('ao,',35)select @s1=left(@s1,len(@s1)-1),@s2=left(@s2,len(@s2)-1)select @s1='select '''+replace(@s1,',',''' union all select ''')+''''
,@s2='select '''+replace(@s2,',',''' union all select ''')+''''create table #t1(id int identity,s1 varchar(10),s2 varchar(10))create table #t2(id int identity,s varchar(10))insert #t1(s1) exec(@s1)insert #t2(s) exec(@s2)select voice as sm,rhyme as ym,count(*) as num into #t_num from T_SyllableFrom
group by voice,rhyme
order by voice,rhyme
declare @id1 int,@s varchar(10),@id2 int
set @id1=1
while @id1<=@num
begin
update A set @s=s2=(select top 1 s from #t2 B where (select num from #t_num where sm=A.s1 and ym=B.s)-(select count(*) from #t1 where s2=B.s)>0 order by newid())
from #t1 A where id=@id1
select @id2=(select top 1 id from #t2 where s=@s)
delete #t2 where id=@id2
select @id1=@id1+1,@id2=0,@s=''
endset @id1=1
declare @b table(id int,orderid int)
while @id1<=@num
begin
insert @b
select top 1 SDid,idorder from T_SyllableFrom A,#t1 B
where voice=B.s1
and rhyme=B.s2
and B.id=@id1
and SDid not in (select id from @b)
order by newid()
set @id1=@id1+1
enddrop table #t1,#t_num,#t2select A.* from T_SyllableFrom A,@b B where A.sdid=B.id and A.idorder=B.orderid
order by sdid,idorder
begin
insert @b
select top 1 SDid,idorder from T_SyllableFrom A,#t1 B
where voice=B.s1
and rhyme=B.s2
and B.id=@id1
and not exists (select 1 from @b where id=A.sdid and orderid=A.idorder)
order by newid()
set @id1=@id1+1
end把这一段改到上面的过程去,就完全正确了
这是用逐步推演的方式,以但是仍然存在无解的风险:
上面的语句中:
update A set @s=s2=(select top 1 s from #t2 B where (select num from #t_num where sm=A.s1 and ym=B.s)-(select count(*) from #t1 where s2=B.s)>0 order by newid())
from #t1 A where id=@id1逐步组合掉韵母,很有可能在子查询:
select top 1 s from #t2 B where (select num from #t_num where sm=A.s1 and ym=B.s)-(select count(*) from #t1 where s2=B.s)>0
在一部分韵母被组合掉后,出现空集合的可能,
特别是如果后边声母与韵母组合数本身很少,前面的声母可能组合完他们的声母,
到后来就很可能完成不了
显然无解的风险比随机的方式会小多了