C# source code, for those that prefer to compile for themselves:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public partial class UserDefinedFunctions
{
[SqlFunction
(
DataAccess = DataAccessKind.None,
SystemDataAccess = SystemDataAccessKind.None,
FillRowMethodName = "FillRow",
IsDeterministic = true,
IsPrecise = true
)
]
public static IEnumerable GetCombinations
(
[SqlFacet(MaxSize = 256, IsNullable = false, IsFixedLength = false)] SqlString input
)
{
// Check for a NULL parameter
if (input.IsNull)
{
return new string[0];
}
// Create a list of string arrays to hold each member of each group
List<string[]> groupList = new List<string[]>();
// Split the input into groups on the semicolon
string[] groups = input.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// For each group, add each item of the group to a string array in the list
for (int i = 0; i < groups.Length; i++)
{
groupList.Add(groups.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
// Do the recursive magic (returns a List of strings, each of which is a combination)
return recursiveAppend(0, groupList);
}
// Called by SQL Server for each member of the List of strings
public static void FillRow(object obj, out SqlString combination)
{
// Remove the final comma and return the combination string as a new row
string output = (string)obj;
output = output.Substring(0, output.Length - 1);
combination = new SqlString(output);
}
// The magic
static List<string> recursiveAppend(int level, List<string[]> inputList)
{
List<string> toReturn = new List<string>();
if (level == inputList.Count)
{
toReturn.Add(String.Empty);
return toReturn;
}
foreach (string item in inputList[level])
{
foreach (string partialList in recursiveAppend(level + 1, inputList))
{
if (!partialList.Contains(item + ','))
{
toReturn.Add(item + "," + partialList);
}
}
}
return toReturn;
}
}
Paul White
SQLPerformance.com
SQLkiwi blog
@SQL_Kiwi