递归存储过程或函数

时间:2014-03-06 05:14:55

标签: c# sql-server tsql

是否有任何方法可以使用类似下面的c#代码存储过程或函数:

我想将此方法转换为T-SQL。

public static IEnumerable<String> GetWords(Int32 length)
{
  if ( length <= 0 ) yield break ;

  for (Char c = '!'; c <= '~'; c++)
  {
    if ( length > 1 )
    {
      foreach ( String restWord in GetWords( length - 1 ) )
        yield return c + restWord;
    }
    else
      yield return "" + c;
  }
}

1 个答案:

答案 0 :(得分:1)

你确实意识到,不管你正在做什么实际上是在生成一系列基数为94的数字...而你所生成的字符串的域变化很大,非常快。例如,使用您的字符集(0x21-0x7E),有

  • 8,836种可能(94 2 )2字符串
  • 830,584可能(94 3 )3个字符的字符串
  • 78,074,896可能(94 4 )4个字符的字符串
  • 当你点击6个字符时,你会看到94 6 或689,869,781,056个字符串来生成。

因此,如果你要这样做,请创建一个SQL Server CLR table-valued function来动态生成它们。

你在构建字符串的方式很可能......在'堆'和字符串实习表中有点难。对于初学者,我会将程序集标记为不通过程序集属性CompilationRelaxationsAttribute进行字符串实习。

并使用一种使用单个固定大小StringBuilder的非递归方法。这是一个SQL Server表值函数,它使用该方法执行代码所做的事情:

using Microsoft.SqlServer.Server;

class MySqlServerDotNetFunctions
{

  [SqlFunction( TableDefinition="id int not null , value varchar(2000)" , FillRowMethodName="FillRow")]
  public static IEnumerable<Tuple<long,StringBuilder>> GenerateStrings( int stringLength )
  {
    const char lowerBound  = '!' ;
    const char upperBound = '~' ;
    if ( stringLength < 1 || stringLength > 2000 ) throw new ArgumentOutOfRangeException("stringLength","string length must be in the range 1-2000" ) ;

    // initialize the stringbuilder
    bool          carry = false ; // carry flag
    StringBuilder sb    = new StringBuilder(new string(lowerBound,stringLength)) ;
    for ( long i = 0 ; !carry && ++i > 0 ; )
    {
      // return the current iteration
      yield return new Tuple<long,StringBuilder>(i,sb) ;

      // increment our string
      int  p     = sb.Length-1 ; // we work right-to-left
      do
      {
        carry = ++sb[p] > upperBound   ;
        if ( carry )
        {
          sb[p] = lowerBound ;
        }
      } while ( carry && --p >= 0 ) ;

    }
  }

  public static void FillRow( object o , out long id , out string value )
  {
    Tuple<long,StringBuilder> item = (Tuple<long,StringBuilder>) o ;

    id    = item.Item1            ;
    value = item.Item2.ToString() ;
    return ;
  }

}