CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
可用分押宝游戏火热进行中... 专题改版:Java Web 专题
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  MS-SQL Server >  基础类

难道就没有可以解决算法!没有分该问题为靠前发了5次了

楼主herr()2005-08-08 17:53:48 在 MS-SQL Server / 基础类 提问

 
  列1   列2   列3   列4  
    p       i     pi        
    b       ao   bao  
    l       an   lan  
    l       i     li  
    p       an   pan  
    p       ao   pao    
    b       i     bi  
    l       an   lan  
    b       an   ban  
  ------------加几个数据帮助理解  
    zh     ai       zhai  
    b       ing     bing  
    p       en       pen  
  .....其它的数据  
                                  --------这个是数据库实际存在的,数据有1-2W数据组合,例要求列1   P出现3次,b出现3次,l出现3次,列2   --i出现3次,ao   出现2次,an   出现4次这样的条件来取数据。是在这些1-2W的数据中   随机符合我这个条件,条件是在变的,例要求   列1(声母)w出现3次,sh出现1次,d出现5次,列2(韵母)   --an出现5次,ao   出现2次,ang   出现2次这样的条件来取数据,也就是说   在去得数据中列1与列2要符合我的   要求   。  
  问题点数:20、回复次数:61Top

1 楼rivery(river)回复于 2005-08-08 18:38:48 得分 0

问一下搂住:  
  例要求列1   P出现3次,b出现3次,l出现3次,列2   --i出现3次,ao   出现2次,an   出现4次这样的条件来取数据。  
  是在原有的数据中找到满足条件的记录还是把列1满足条件的记录和列2满足条件的记录组合到一起生成一个新的结果集?  
  Top

2 楼herr()回复于 2005-08-08 21:31:14 得分 0

是在原有的数据中找到满足条件的记录。  
   
    就是取的结果集中,列1和列2各列统计出满足我的条件就可以。这个条件要求可以自己定义,就是说   要出现列1(声母)、   列2(韵母)具体内容及内容数量可以根据需要来定义。  
   
  不知道我说明白了。辛苦你了!  
   
  =============  
  另附带说明列1是声母;   列2是韵母;列3是拼音;列4是词;Top

3 楼jimnet(jim)回复于 2005-08-09 04:56:00 得分 0

不懂Top

4 楼zhhlong(海水深蓝)回复于 2005-08-09 09:27:51 得分 0

不知所云^^^^^^^^^^^Top

5 楼coolingpipe(冷箫轻笛)回复于 2005-08-09 11:58:37 得分 0

确实没有什么算法可言  
   
  楼主倒不如写下你到底想实现什么功能  
  大家一起想办法  
  这个问题是没有什么算法的!Top

6 楼rivery(river)回复于 2005-08-09 16:18:37 得分 8

/*  
  处理思想:由外部条件组合成一个结果集,与原结果集联合查询。  
  说明:外部条件列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)  
  )    
  as  
   
  begin  
  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  
   
  */  
  Top

7 楼rivery(river)回复于 2005-08-09 16:19:57 得分 0

忘记屏蔽调试时的  
  drop   procedure   getresult  
  了。Top

8 楼rivery(river)回复于 2005-08-09 16:26:51 得分 0

告诉你个秘诀啊你自己回复一次,你的帖子就到前面去了。  
  同时很多人都想帮你的。但是真的无法理解你的意思。我也不知道理解对没。  
  其实这里的人是最热心的,每个问题他们都想能够得到解决。  
  Top

9 楼yaozw_mountain(山林)回复于 2005-08-09 18:36:15 得分 0

例中条件:要求   列1(声母)w出现3次,sh出现1次,d出现5次,  
  列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,1Top

10 楼filebat(Mark)回复于 2005-08-09 19:13:06 得分 0

rivery,你真有耐心啊。  
  你贴的代码,滚了五下滚轮才滚完。  
  楼主,不给他全分,就不厚道哦。Top

11 楼rivery(river)回复于 2005-08-09 21:16:48 得分 0

^_^,关键搂住似乎对这里有点灰心。  
  而我又感觉自己理解了有点他的意思(也不知道对不),  
  所以就耗费了半天的时间弄了一下,倒是排列组合难住了。没想到好的方法。  
  楼上有空帮忙写个sql的某个字符串的排列组合的算法。  
  Top

12 楼herr()回复于 2005-08-09 22:58:18 得分 0

rivery(river)   辛苦了,我TESTTop

13 楼yaozw_mountain(山林)回复于 2005-08-11 17:45:55 得分 2

 
  --   感谢     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.i  
   
  update   #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  
  end  
   
  select   count(DISTINCT   h)   from   @tout  
  select   *   from   @tout   order   by   h,   id0  
   
  drop   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  
  */Top

14 楼herr()回复于 2005-08-11 22:10:04 得分 0

rivery   超出了存储过程、函数、触发器或视图的最大嵌套层数(最大层数为   32)。Top

15 楼j9988(j9988)回复于 2005-08-11 22:43:42 得分 10

有几项你没说明白:  
   
  1.这表你应该有个主键.比如ID之类的.否则你组合出来的结果抽那一条没什么意思.  
   
  2.随机组合容易.但不存在的组合,你得事先剔除.比如:   g   k   h   和   ian   组合就不存在.是前台去除还是后台处理?  
   
  后台处理:  
  sekect   distinct   列1,列2,列3   into   NewTable   from   YourTable    
  先产生一个可能的组合表.  
   
  3.因为以上原因,传入的条件是否有所限制??  
   
  4.你的表二万多记录,是所有汉字都存在?   还是其它什么?   表述不够细.  
   
  给出真实的表结构和内容.和你如此查询的真实目的与用处.   这样大家也好看看.  
  Top

16 楼herr()回复于 2005-08-11 23:18:19 得分 0

1.这表你应该有个主键.比如ID之类的.否则你组合出来的结果抽那一条没什么意思.  
     答: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.你的表二万多记录,是所有汉字都存在?   还是其它什么?   表述不够细.  
  答:是我们试题需要的相关字。相关看上述描述  
  Top

17 楼j9988(j9988)回复于 2005-08-11 23:38:00 得分 0

因为数据库随机取数,可以对横向处理,对纵向处理恐怕很难.  
  只有象以上回答一样先随机组合出一组可能有组合.  
  然后再随机从题库出找抽出结果.  
  所以还是随机组合.这样的后果也许你数据库中有符合要求的结果.但抽不出足额的记录.  
   
   
  Top

18 楼j9988(j9988)回复于 2005-08-12 00:00:30 得分 0

--b出现50次,l出现20次,zh出现32次   韵母ao出现12次,ban出现38次,en出现50次。  
   
  --1.先把声母韵母要求的记录组存入表  
   
  declare   @s1   varchar(8000),@s2   varchar(8000)  
  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.id  
   
  OPEN   c  
   
  FETCH   NEXT   FROM   authors_cursor    
  INTO   @声母,@韵母  
   
  WHILE   @@FETCH_STATUS   =   0  
  begin  
   
  insert   @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   源表   )  
   
   
  Top

19 楼j9988(j9988)回复于 2005-08-12 00:07:52 得分 0

--别忘了关闭游标  
          CLOSE   c        
          DEALLOCATE   c  
   
  就当所有组合都存在.都可以找出记录.如果组合不存在,  
  在组合结果时要先调整.比如:  
  调束措失:  
  select   列1,列2,count(*)   存在记录数   into   newTable   from   源表   group   by   列1,列2  
  这样你在传入条件时先做些判断,适当调整随机组合的声母韵母结果.  
   
  然后再随机抽取.Top

20 楼j9988(j9988)回复于 2005-08-12 01:42:14 得分 0

--错了,要改一下  
  WHILE   @@FETCH_STATUS   =   0  
  begin  
   
  insert   @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  
  Top

21 楼herr()回复于 2005-08-12 09:15:18 得分 0

j9988   辛苦了     我TEST   是否可以满足Top

22 楼j9988(j9988)回复于 2005-08-12 10:10:52 得分 0

--b出现50次,l出现20次,zh出现32次   韵母ao出现12次,ban出现38次,en出现50次。  
   
  --1.先把声母韵母要求的记录组存入表  
   
  declare   @s1   varchar(8000),@s2   varchar(8000)  
  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.id  
   
  OPEN   c  
   
  FETCH   NEXT   FROM   authors_cursor    
  INTO   @声母,@韵母  
   
  WHILE   @@FETCH_STATUS   =   0  
  begin  
   
  insert   @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)---这儿改一下.Top

23 楼j9988(j9988)回复于 2005-08-12 10:12:19 得分 0

应该基本上可以符合你的要求,但缺点是:就是怕组合出的结果有些在源表中找不到.Top

24 楼yaozw_mountain(山林)回复于 2005-08-12 10:38:49 得分 0

怎么像   拼音练习  
   
  “在提取100个字中,要求含声母b出现50次,l出现20次,zh出现32次   韵母ao出现12次,ban出现38次,en出现50次”:如果只有   b,l,zh;   ao,ban,en组合怎么也得不到100个汉字,是不是有其他字母,只是不计数??  
   
    j9988(j9988)   的  
  “--用游标100次循环随机抽出符合条件不重复的ID  
  declare   c   cursor   for  
  select   A.s,B,s   from   #t1   A,@a   B   where   A.id=B.id  
  ”  
  这样撞大运,成功概率不知怎样  
  Top

25 楼herr()回复于 2005-08-12 10:41:11 得分 0

where   列1=@声母   and   列1=@韵母   --->应该是where   列1=@声母   and   列2=@韵母   吧  
  Top

26 楼prcgolf(小鸟)回复于 2005-08-12 11:13:27 得分 0

upTop

27 楼j9988(j9988)回复于 2005-08-12 11:59:30 得分 0

where   列1=@声母   and   列1=@韵母   --->应该是where   列1=@声母   and   列2=@韵母   吧  
  是的.错了  
   
   
  Top

28 楼herr()回复于 2005-08-12 12:07:17 得分 0

我给你留言了,请查收Top

29 楼j9988(j9988)回复于 2005-08-12 12:08:30 得分 0

yaozw_mountain(山林)   :  
   
  "“--用游标100次循环随机抽出符合条件不重复的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   结果集.  
   
   
   
   
   
   
  Top

30 楼j9988(j9988)回复于 2005-08-12 12:10:05 得分 0

declare   @b   table(id   int)  
  Top

31 楼yaozw_mountain(山林)回复于 2005-08-12 14:05:24 得分 0

“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个汉字,是不是有其他字母,只是不计数??  
   
  还是不是因为包含多音字。  
   
  还有:  
   
  声母/韵母个数(不包含重复值)最多会有多少?  
  Top

32 楼yaozw_mountain(山林)回复于 2005-08-12 14:14:51 得分 0

如果随机排序得到结果集的概率较大,就可以循环随机排序。否则需要较长时间了Top

33 楼rivery(river)回复于 2005-08-12 14:17:29 得分 0

热闹了,高人也就出现了。  
  齐心协力,问题也会解决了。  
  期待着搂住满怀欢喜的那个帖子:问题都解决了!最终的解决代码如下。。。。。。Top

34 楼yaozw_mountain(山林)回复于 2005-08-12 14:26:21 得分 0

declare   @t   table(s1   varchar(40),   s2   varchar(40),   cnt   int)  
  insert   into   @t(s1,s2,cnt)  
  select   列1,列2,count(*)   from   源表   group   by   列1,列2  
   
  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>   isnull(   (  
          select   cnt   from   @t   b   where   b.s1   =   r.s1   and   b.s2=   r.s2  
          ),   0)  
      )  
  --   ok  
   
  Top

35 楼herr()回复于 2005-08-12 14:31:19 得分 0

yaozw_mountain(山林)    
  --“在提取100个字中,要求含声母b出现50次,l出现20次,zh出现32次   韵母ao出现12次,ban出现38次,en出现50次”:如果只有   b,l,zh;   ao,ban,en组合怎么也得不到100个汉字,是不是有其他字母,只是不计数??  
  \\般来说在老师出题目的时候他回作细小的估计,基本是可以组合出个数,以上是我写的例数量,在这几个里是不可能.  
   
   
  --还是不是因为包含多音字。  
   \\是的  
   
  Top

36 楼yaozw_mountain(山林)回复于 2005-08-12 14:35:08 得分 0

declare   @t   table(s1   varchar(40),   s2   varchar(40),   cnt   int)  
  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  
      )  
  --   okTop

37 楼j9988(j9988)回复于 2005-08-12 21:05:12 得分 0

惭愧!   山林说的是对的.确实存在这种情况.   对不起!!!!  
   
  会有解决方法.正思考中....可惜现在喝多了.Top

38 楼j9988(j9988)回复于 2005-08-13 11:02:25 得分 0

declare   @s1   varchar(8000),@s2   varchar(8000)  
  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=''  
  end  
   
  set   @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  
  end  
   
  select   *   from   T_SyllableData     where   SDid   in   (select   id   from   @b)  
  order   by   voice0,rhyme0  
  --select   *   from   #t2  
   
  drop   table   #t1,#t_num,#t2Top

39 楼j9988(j9988)回复于 2005-08-13 11:02:58 得分 0

完成了!Top

40 楼j9988(j9988)回复于 2005-08-13 11:04:08 得分 0

所有组合绝对可以在源表中找到.Top

41 楼j9988(j9988)回复于 2005-08-13 11:09:45 得分 0

--与前面不同之处做一些注释补充  
  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  
  Top

42 楼herr()回复于 2005-08-14 14:04:22 得分 0

j9988(j9988)   发信息给你,结构变动.Top

43 楼prcgolf(小鸟)回复于 2005-08-14 17:45:07 得分 0

upTop

44 楼j9988(j9988)回复于 2005-08-14 23:18:37 得分 0

create   table   T_SyllableFrom   (  
        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  
   
   
  这样表修改后,可扩展性大大增强.你原来的表只能固定最多四字词.这样一改随意性就强了.  
  原表如果碰到"一夫挡关,万夫莫开"   或   "不管三七二十一"   就得改表结构,这是表设计中最忌讳的.  
   
  Top

45 楼j9988(j9988)回复于 2005-08-14 23:22:03 得分 0

从表按要求建立好后,执行以下过程,出100道题,在我的S1.7   的PC上不到2秒.  
   
  declare   @s1   varchar(8000),@s2   varchar(8000)  
  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=''  
  end  
   
  set   @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  
  end  
   
  drop   table   #t1,#t_num,#t2  
   
  select   A.*   from   T_SyllableFrom   A,@b   B   where   A.sdid=B.id   and   A.idorder=B.orderid  
  order   by   sdid,idorder  
   
  Top

46 楼j9988(j9988)回复于 2005-08-14 23:30:47 得分 0

喔,while这一段没改好,应该这样:    
   
  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   not   exists   (select   1   from   @b   where   id=A.sdid   and   orderid=A.idorder)  
  order   by   newid()  
  set   @id1=@id1+1  
  end  
   
  把这一段改到上面的过程去,就完全正确了Top

47 楼prcgolf(小鸟)回复于 2005-08-15 09:06:53 得分 0

upTop

48 楼herr()回复于 2005-08-15 09:21:00 得分 0

多音节,如何来解决Top

49 楼yaozw_mountain(山林)回复于 2005-08-16 18:34:07 得分 0

j9988注意不错!  
  这是用逐步推演的方式,以但是仍然存在无解的风险:  
  上面的语句中:  
  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  
  在一部分韵母被组合掉后,出现空集合的可能,  
  特别是如果后边声母与韵母组合数本身很少,前面的声母可能组合完他们的声母,  
  到后来就很可能完成不了  
   
   
  显然无解的风险比随机的方式会小多了  
   
   
   
  Top

50 楼yaozw_mountain(山林)回复于 2005-08-16 18:39:10 得分 0

sorry!   错字太多  
   
  如果后边声母与韵母组合数本身很少,前面的声母可能组合完他们的韵母Top

51 楼j9988(j9988)回复于 2005-08-17 00:08:21 得分 0

yaozw_mountain(山林)   所说的出现过.仅是在类似于P   50   L   32   B   18   这类情况下.  
   
  而实际情况是:出100题是:p(5)   l(3)   b(7)..........   不会是仅两三个字母.  
  分别各有十几二十个声母.  
   
  目前herr给的实际表中仅4000多记录.P   50   L   32   B   18   这类情况,十次仅三五次得到99,98,97条记录.其它全是100条记录  
  出100题是:p(5)   l(3)   b(7)..........   可以做到100题出全.  
  所以过程还是可靠的.  
   
  如果正式运行,楼主说有二万多记录.那更是运行没问题.  
   
  仅是提供一个方法而已.细节还是要自已去做.  
  Top

52 楼yaozw_mountain(山林)回复于 2005-08-17 09:00:50 得分 0

 
   
  --*************************   <<   No.   3   >>*****************************************************  
  --   <<   该算法的思想是:在源中得到声母-韵母对的最大数,在这个范围内取数组合中满足条件即为组合解   >>  
   
  --主表数据  
  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)  
  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   )  
  create   table   #tc2   (   i   varchar(40),   n   int   )  
   
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#g')   and   type='U'   )   drop   table   #g  
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#tgout')   and   type='U'   )   drop   table   #tgout  
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#tout')   and   type='U'   )   drop   table   #tout  
  create   table   #g   (i   int   IDENTITY(0,1)   PRIMARY   KEY,   c1   varchar(10),c2   varchar(10),   n   int   )  
  create   table   #tgout   (i   int   IDENTITY(0,1)   PRIMARY   KEY,   s   varchar(4000)   )  
  create   table   #tout   (id   int   IDENTITY(0,1)   PRIMARY   KEY,id0   int,   c1   varchar(10),c2   varchar(10),grp   varchar(300))  
   
  CREATE   INDEX   index_g_c1   ON   #g   (   c1   )  
  CREATE   INDEX   index_g_c2   ON   #g   (   c2   )  
  CREATE   INDEX   index_tout_c2   ON   #tout   (   c1,c2   )  
   
   
  declare   @sqlstr   as   varchar(8000),   @m1   as   int  
  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   )  
   
  select   @m1   =   count(*)   from   #tc1  
  if   (select   sum(n)   from   #tc1)   <>   (   select   sum(   n)   from   #tc2)     return   ---1     Error   Input  
   
  insert   into   #g   (c1,   c2,   n   )  
  select   c1,c2,   count(*)   from   @tsrc,(  
  select   a.i   i1,   b.i   i2   from   #tc1   a,   #tc2   b  
  )   x    
  where   x.i1   =   c1   and   x.i2   =   c2  
  group   by   c1,c2  
   
  declare   @max   as   int,   @max2   as   int,   @mg   as   int,   @i   as   int  
  select   @max=   count(*)   from   #g  
  select   @mg   =   max(n)   +   1   from   #g  
   
  if   exists(select   *   from   #tc1   x   where(select   isnull(sum(n),0)   from   #g   g   where   x.i=g.c1)<   x.n)   return     ---2No   Result  
  if   exists(select   *   from   #tc2   x   where(select   isnull(sum(n),0)   from   #g   g   where   x.i=g.c2)<   x.n)   return     ---2No   Result  
   
   
  --   开始处理  
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#n')   and   type='U'   )   drop   table   #n  
  --create   table   #n   (i   int   IDENTITY(0,1)   PRIMARY   KEY   )  
   
  SET   ROWCOUNT   @mg  
  select   IDENTITY(int,   0,1   )   as   i  
  into   #n  
  from   sysobjects   a,   sysobjects   b,   sysobjects   c  
  SET   ROWCOUNT   0  
   
  /*  
  select   a1.i+','+a2.i+','+a3.i+','+...  
  from   (select   top   ?1   i   from   #n)   a1,(select   top   ?2   i   from   #n)   a2,...  
  where   (a1.i   +...)c1=??  
  and         ............  
  and       (a1.i   +...)c2=??  
  and         ............  
  */  
  declare   @s1   as   varchar(4000),   @s2   as   varchar(4000),   @sx1   varchar(4000),   @sx2   varchar(4000),   @tc_i   varchar(20),   @tc_n   int  
   
  --   where   form1  
  DECLARE   @cursor_tc   CURSOR  
   
  SET   @cursor_tc   =   CURSOR   FORWARD_ONLY   READ_ONLY   FOR  
  select   i,n   from   #tc1  
   
  set   @sx1=''  
  OPEN   @cursor_tc  
  FETCH   NEXT   FROM   @cursor_tc   INTO   @tc_i,   @tc_n  
  WHILE   @@FETCH_STATUS   =   0  
  BEGIN  
  set   @s1=''  
  select   @s1=@s1   +   '+a'+cast(i   as   varchar)+'.i'   from   #g   g   where   g.c1   =   @tc_i  
   
  set   @sx1=@sx1   +   '   and   '+STUFF(@s1,1,1,'')   +'='   +   cast(@tc_n   as   varchar)  
   
  FETCH   NEXT   FROM   @cursor_tc   INTO   @tc_i,   @tc_n  
  END  
  CLOSE   @cursor_tc  
  set   @sx1=   STUFF(@sx1,2,3,'where')  
   
  SET   @cursor_tc   =   CURSOR   FORWARD_ONLY   READ_ONLY   FOR  
  select   i,n   from   #tc2  
   
  set   @sx2=''  
  OPEN   @cursor_tc  
  FETCH   NEXT   FROM   @cursor_tc   INTO   @tc_i,   @tc_n  
  WHILE   @@FETCH_STATUS   =   0  
  BEGIN  
  set   @s1=''  
  select       @s1=@s1   +   '+a'+cast(i   as   varchar)+'.i'   from   #g   g   where   g.c2   =   @tc_i  
   
  set   @sx2=@sx2   +   '   and   '+STUFF(@s1,1,1,'')   +'='   +   cast(@tc_n   as   varchar)  
   
  FETCH   NEXT   FROM   @cursor_tc   INTO   @tc_i,   @tc_n  
  END  
  CLOSE   @cursor_tc  
  DEALLOCATE   @cursor_tc  
  --   get   @sx1,   @sx2 ...>>   271  
   
   
  set   @s1='';   set   @s2=''  
  select     @s1=@s1   +   '+str(a'+cast(i   as   varchar)+'.i,4)',    
  @s2=@s2   +   ',(select   i   from   #n   where   i<'+cast(n+1   as   varchar)+')a'+cast(i   as   varchar)  
  from   #g   order   by   i  
   
  set   @s1=STUFF(@s1,1,1,'');   set   @s2=STUFF(@s2,1,1,'')  
   
  set   @sqlstr   =   'select   '+@s1   +'   from   '   --     +   @s2    
  /*   --   where   form2  
  set   @sx1   =   '   where   not   exists(select   *   from   #tc1   x   where(select   isnull(sum(n),0)   from(select   cast(substring('+@s1+',g.i*4+1,4)   as   int)n   from   #g   g   where   x.i=g.c1)n)<>x.n)'  
  set   @sx2   =       '   and   not   exists(select   *   from   #tc2   x   where(select   isnull(sum(n),0)   from(select   cast(substring('+@s1+',g.i*4+1,4)   as   int)n   from   #g   g   where   x.i=g.c2)n)<>x.n)'  
  */  
  /*   --   where   form3  
  set   @sqlstr=   'select   s   from(select   '+@s1   +'   s   from   '   +   @s2   +  
  ')a   where   not   exists(select   *   from   #tc1   x   where(select   isnull(sum(n),0)   from(select   cast(substring(a.s,g.i*4+1,4)   as   int)n   from   #g   g   where   x.i=g.c1)n)<>x.n)'+  
          '   and   not   exists(select   *   from   #tc2   x   where(select   isnull(sum(n),0)   from(select   cast(substring(a.s,g.i*4+1,4)   as   int)n   from   #g   g   where   x.i=g.c2)n)<>x.n)'  
  */  
  insert   into   #tgout(s)exec(@sqlstr   +   @s2   +   @sx1   +   @sx2)  
   
  select   *   from(  
  select   a.i   idgrp,   cast(substring(a.s,g.i*4+1,4)   as   int)n,g.n   m,c1,c2  
  from   #g   g,   #tgout   a)x  
  where   n>0  
  order   by   idgrp,c1,c2  
  /*  
  得到所有解组合集(每个解分组中声母-韵母对提取n个):  
  idgrp n m c1 c2  
  解分组/提取数/源中最大数/声母-韵母对  
  ---------------------------------------  
  0 1 1 b an  
  0 1 1 l i  
  0 1 1 p an  
  0 1 1 p ao  
  1 1 1 b ao  
  1 1 2 l an  
  1 1 1 p an  
  1 1 1 p i  
  2 1 1 b i  
  2 1 2 l an  
  2 1 1 p an  
  2 1 1 p ao  
  3 1 1 b an  
  3 1 2 l an  
  3 1 1 p ao  
  3 1 1 p i  
  这里已经得到所有解的组合,只需要从源中提取声母-韵母对,  
  可以随机方式取,也可以按照m中取n的组合得到所有解。  
  */  
  Top

53 楼yaozw_mountain(山林)回复于 2005-08-17 09:03:44 得分 0

 
  --   按照m中取n的组合得到所有解  
   
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#tid0')   and   type='U'   )   drop   table   #tid0  
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#tidx')   and   type='U'   )   drop   table   #tidx  
  if   exists(   select   *   from   tempdb..sysobjects   where   id   =   OBJECT_ID('tempdb..#tCmn')   and   type='U'   )   drop   table   #tCmn  
  create   table   #tidx   (id   int   IDENTITY(0,1)   PRIMARY   KEY,   id0   int,   i   int,   g   int   )  
  create   table   #tCmn   (id   int   IDENTITY(0,1)   PRIMARY   KEY,   m   int,   n   int,   e   varchar(4000)   )  
  CREATE   INDEX   index_tCmn_mn   ON   #tCmn(   m,   n   )  
  CREATE   INDEX   index_tidx_g   ON   #tidx(   g   )  
   
  declare   @tc_gi   int,   @tc_m   int  
  DECLARE   @cursor_tg     CURSOR  
  DECLARE   @cursor_tg2   CURSOR  
   
  SET   @cursor_tg   =   CURSOR   FORWARD_ONLY   READ_ONLY   FOR  
  select   str(i,4),s   from   #tgout  
   
  OPEN   @cursor_tg  
  FETCH   NEXT   FROM   @cursor_tg   INTO   @tc_i,   @s1  
  WHILE   @@FETCH_STATUS   =   0  
  BEGIN  
  delete   from   #tidx  
   
  SET   @cursor_tg2   =   CURSOR   FORWARD_ONLY   READ_ONLY   FOR  
  select   g.i,cast(substring(@s1,g.i*4+1,4)   as   int)n,   g.n   m  
  from   #g   g   where   cast(substring(@s1,g.i*4+1,4)   as   int)>0  
   
  OPEN   @cursor_tg2  
  set   @s2   ='';   set   @sx1   ='';   set   @sx2   =''  
  FETCH   NEXT   FROM   @cursor_tg2   INTO   @tc_gi,   @tc_n,   @tc_m  
  WHILE   @@FETCH_STATUS   =   0  
  BEGIN  
  if   not   exists(select   *   from   #tCmn   where   m=@tc_m   and   n=@tc_n   )  
  begin --     .do   Cm,n   to   add  
  --   Cm,n   (m中取n的组合算法)  
  declare   @cm   int,   @cn   int,   @cd   int,   @ca   int,   @strExp   varchar(4000),   @va   char(4)  
  set   @cm   =@tc_m;   set   @cn=@tc_n  
   
  set   @strExp   =   space(   @cn*4   );   set   @cd   =1;   set   @ca   =1  
  while(1=1) --   Loop:a(1....n)  
  begin  
  --     //   (XLoop:)b   (   V(a-1)+1....   m-n+a   )  
  if   @cd=1  
  if   @ca<=1  
  set   @va   =1  
  else  
  set   @va   =   cast(   substring(@strExp,   (@ca-1)   *4-3,4)   as   int)   +1  
  else  
  set   @va   =   cast(   substring(@strExp,   @ca   *4-3,4)   as   int)   +1  
   
  set   @strExp   =   stuff(@strExp,     @ca   *4-3,   4,   str(@va,4)   )  
  set   @cd   =-1  
  if(   @va   >   @cm-@cn+@ca   )  
  if(@ca<=1)  
    BREAK --   exit   Loop:   finish  
  else  
  set   @ca   =   @ca   -1  
  else  
  if(@ca>=@cn)  
  begin  
  --   export   data  
  insert   #tCmn(m,n,e)   values(   @cm,@cn,@strExp)  
  end  
  else  
  begin  
  set   @ca   =   @ca   +1  
  set   @cd   =1  
  end  
  end  
  --   End   of   Cm,n    
  end  
  select   IDENTITY(int,1,1)   as   i,   id   id0   into   #tid0    
  from   @tsrc   t,#g   g   where   t.c1=g.c1   and   t.c2=g.c2   and   g.i=@tc_gi  
   
  insert   into   #tidx(i,id0,g)   select   i,id0,@tc_gi   g   from   #tid0  
   
    drop   table   #tid0  
  set   @s2   =   @s2+   '+str(t'+cast(@tc_gi   as   varchar)+'.id,4)'  
  set   @sx1   =   @sx1   +'(select   id,e   from   #tCmn   where   m='+cast(@tc_m   as   varchar)+'   and   n='+cast(@tc_n   as   varchar)+')t'+cast(@tc_gi   as   varchar)+','  
  set   @sx2   =   @sx2   +'   when   '+cast(@tc_gi   as   varchar)+'   then   t'+cast(@tc_gi   as   varchar)+'.e'  
   
  FETCH   NEXT   FROM   @cursor_tg2   INTO   @tc_gi,   @tc_n,   @tc_m  
  END  
  CLOSE   @cursor_tg2  
  set   @s2   =   'select   '''+@tc_i+'''+'+@s2+',y.id0   from   '  
  set   @sx2   =   '(select   x.g,x.i,x.id0   from   #tidx   x,#g   g   where   cast(substring('''+@s1+''',g.i*4+1,4)   as   int)>0   and   x.g=g.i)y   where   CHARINDEX(str(y.i,4),case   y.g'+@sx2+'   end)>0'  
  --   按照解的组合从源中提取声母-韵母对,按照m中取n的组合,再各声母-韵母对交叉,得到该组中的所有解。  
  insert   into   #tout(grp,id0)   exec(@s2   +   @sx1   +   @sx2   )  
  -- select   str(   t(@g.i1).id,4)+str(   t(@g.i2).id,4)+...,y.id0   from  
  -- (select   id,e,(@g.i1)   g   from   @tCmn   where   m=@?   and   n=@?)t(@g.i1),  
  -- (select   id,e,(@g.i2)   g   from   @tCmn   where   m=@?   and   n=@?)t(@g.i2),  
  -- .....,  
  --   (select   x.g,x.i,x.id0   from   #tidx   x,#g   g   where   cast(substring(a.s,g.i*4+1,4)   as   int)>0   and   x.g=g.i)y  
  -- where   CHARINDEX(str(y.i,4),   y.g:t(@g.i?).g?t(@g.i?).e)>0      
   
   
  FETCH   NEXT   FROM   @cursor_tg   INTO   @tc_i,@s1  
  END  
  CLOSE   @cursor_tg  
  DEALLOCATE   @cursor_tg  
  DEALLOCATE   @cursor_tg2  
   
   
   
  update   #tout   set   c1=   t.c1,c2=t.c2  
  from   @tsrc   t   ,   #tout   o  
  where   t.id=o.id0  
   
  select   count(DISTINCT   grp)   from   #tout  
  select   *   from   #tout   order   by   grp,   id0  
   
  drop   table   #tc1  
  drop   table   #tc2  
  Top

54 楼yaozw_mountain(山林)回复于 2005-08-17 09:11:51 得分 0

/*  
  注:上面几贴是相连的  
  --   这里得到的与以前提供算法的解集相同(7)  
  3 3 l i       0       0       0       0       0  
  1 4 p an       0       0       0       0       0  
  2 5 p ao       0       0       0       0       0  
  0 8 b an       0       0       0       0       0  
  10 0 p i       1       1       0       0       0  
  8 1 b ao       1       1       0       0       0  
  4 2 l an       1       1       0       0       0  
  6 4 p an       1       1       0       0       0  
  11 0 p i       1       2       0       0       0  
  9 1 b ao       1       2       0       0       0  
  7 4 p an       1       2       0       0       0  
  5 7 l an       1       2       0       0       0  
  12 2 l an       2       1       0       0       0  
  14 4 p an       2       1       0       0       0  
  16 5 p ao       2       1       0       0       0  
  18 6 b i       2       1       0       0       0  
  15 4 p an       2       2       0       0       0  
  17 5 p ao       2       2       0       0       0  
  19 6 b i       2       2       0       0       0  
  13 7 l an       2       2       0       0       0  
  26 0 p i       3       0       1       0       0  
  22 2 l an       3       0       1       0       0  
  24 5 p ao       3       0       1       0       0  
  20 8 b an       3       0       1       0       0  
  27 0 p i       3       0       2       0       0  
  25 5 p ao       3       0       2       0       0  
  23 7 l an       3       0       2       0       0  
  21 8 b an       3       0       2       0       0  
  */  
  Top

55 楼prcgolf(小鸟)回复于 2005-08-17 14:09:06 得分 0

upTop

56 楼yaozw_mountain(山林)回复于 2005-08-17 15:40:09 得分 0

一点改进,   提高速度:  
   
  CREATE   INDEX   index_tidx_i   ON   #tidx(   i   )  
   
  .......  
   
  /*  
  select   IDENTITY(int,1,1)   as   i,   id   id0   into   #tid0    
  from   @tsrc   t,#g   g   where   t.c1=g.c1   and   t.c2=g.c2   and   g.i=@tc_gi  
  insert   into   #tidx(i,id0,g)   select   i,id0,@tc_gi   g   from   #tid0  
    drop   table   #tid0  
  */  
  insert   into   #tidx(i,id0,g)  
  select   -1   i,   id   id0,   @tc_gi   g  
  from   @tsrc   t,#g   g   where   t.c1=g.c1   and   t.c2=g.c2   and   g.i=@tc_gi  
  set   @i=0  
  update   #tidx   set   @i=i=@i+1   where   i=-1  
  Top

57 楼softj(天地客人<最近很迷茫>)回复于 2005-08-17 18:01:45 得分 0

从楼上到楼下,一共走了几个小时,看明白一点,可是更好的方法还没有想出!先UP一下吧,  
   
  若能想出好方法,一定来贴!Top

58 楼herr()回复于 2005-08-20 11:29:54 得分 0

UPTop

59 楼herr()回复于 2005-08-20 14:48:52 得分 0

j9988(j9988)   根据你的方法   有点问题   看到了联系啊   我给你Q   留言了Top

60 楼herr()回复于 2005-08-20 15:30:59 得分 0

yaozw_mountain(山林)   速度不可取10分钟   都不不来,我的数据5万   去60条Top

61 楼yaozw_mountain(山林)回复于 2005-08-22 14:21:03 得分 0

herr():    
  完成第一步:得到所有解组合集,    
  不执行第二步(m中取n的组合,循环中Cm,n和drop   table   #tid0比较费时)  
  用时是多少?Top

相关问题

  • 高分求算法!!
  • 500分求算法……
  • 高分求算法!
  • 高分求算法
  • 100分求算法
  • 高分求算法。
  • 20分,求算法
  • 高分求算法!
  • !!!!!高分求算法.....!!
  • 满分求算法。

关键词

  • 算法
  • 组合
  • 数据
  • 排列
  • 声母
  • ao
  • 韵母
  • union
  • tidx
  • 字符串

得分解答快速导航

  • 帖主:herr
  • rivery
  • yaozw_mountain
  • j9988