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

解决方案 »

  1.   

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

  2.   

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

  3.   

    例中条件:要求 列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,1
      

  4.   

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

  5.   

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

  6.   

    rivery(river) 辛苦了,我TEST
      

  7.   


    -- 感谢  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
    */
      

  8.   

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

  9.   

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

  10.   

    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.你的表二万多记录,是所有汉字都存在? 还是其它什么? 表述不够细.
    答:是我们试题需要的相关字。相关看上述描述
      

  11.   

    --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.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 源表 )
      

  12.   

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

  13.   

    --错了,要改一下
    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
      

  14.   

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

  15.   

    --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.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)---这儿改一下.
      

  16.   

    怎么像 拼音练习“在提取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

    这样撞大运,成功概率不知怎样
      

  17.   

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

  18.   

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

  19.   

    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 结果集.
      

  20.   

    declare @b table(id int)
      

  21.   

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

  22.   

    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,列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
      

  23.   

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

  24.   

    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
      )
    -- ok
      

  25.   

    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=''
    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
      

  26.   

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

  27.   

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

  28.   

    从表按要求建立好后,执行以下过程,出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=''
    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
      

  29.   

    喔,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把这一段改到上面的过程去,就完全正确了
      

  30.   

    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
    在一部分韵母被组合掉后,出现空集合的可能,
    特别是如果后边声母与韵母组合数本身很少,前面的声母可能组合完他们的声母,
    到后来就很可能完成不了
    显然无解的风险比随机的方式会小多了
      

  31.   

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