Double Delimited String Parsing and Re-Concatenation Help

  • I have a table with a column of double delimited strings. I need to break it out into all possible combinations without repeats and without repeats from one outer group to another. For example:

    CREATE TABLE #TmpTbl (TblID INT PRIMARY KEY, MultiDelimStr VARCHAR(255))

    INSERT #TmpTbl ( TblID, MultiDelimStr )

    SELECT 101, 'Orange,Apple;Orange,Grape,Banana;Apple,Kiwi,Grape'

    UNION

    SELECT 202, 'Grape,Apple;Orange,Grape,Banana;Peach,Kiwi,Grape'

    UNION

    SELECT 303, 'Orange;Peach,Grape,Banana;Apple,Kiwi;Tangerine,Grapefruit'

    From this I need the following result set:

    101Orange,Grape,Apple

    101Orange,Grape,Kwi

    101Orange,Banana,Apple

    101Orange,Banana,Kiwi

    101Orange,Banana,Grape

    101Apple,Orange,Kiwi

    101Apple,Orange,Grape

    101Apple,Grape,Kiwi

    101Apple,Banana,Kiwi

    101Apple,Banana,Grape

    202Grape,Orange,Peach

    202Grape,Orange,Kiwi

    202Grape,Banana,Peach

    202Grape,Banana,Kiwi

    202Apple,Orange,Peach

    202Apple,Orange,Kiwi

    202Apple,Orange,Grape

    202Apple,Grape,Peach

    202Apple,Grape,Kiwi

    202Apple,Banana,Grape

    202Apple,Banana,Peach

    202Apple,Banana,Kiwi

    303Orange,Peach,Apple,Tangerine

    303Orange,Peach,Apple,Grapefruit

    303Orange,Peach,Kiwi,Tangerine

    303Orange,Peach,Kiwi,Grapefruit

    303Orange,Grape,Apple,Tangerine

    303Orange,Grape,Apple,Grapefruit

    303Orange,Grape,Kiwi,Tangerine

    303Orange,Grape,Kiwi,Grapefruit

    303Orange,Banana,Apple,Tangerine

    303Orange,Banana,Apple,Grapefruit

    303Orange,Banana,Kiwi,Tangerine

    303Orange,Banana,Kiwi,Grapefruit

    But the following row would be incorrect:

    101Apple,Orange,Apple

    Please, also note that I can count on at least 1 semicolon or up to 4, but no more than 4 per record. I donโ€™t want to separate the rows with 1 semicolon and process them before moving on to the rows with 2 semicolons, etc.

    I thought a double parse routine would get me close to where I want to be, but I canโ€™t figure out how to put it back together again in the order my requirements desire. To break it out I have used:

    SELECT FruitID, MultiDelimStr

    ,RANK() OVER(PARTITION BY FruitID ORDER BY N) AS GroupID

    ,SUBSTRING(';'+MultiDelimStr+';',N+1,CHARINDEX(';',';'+MultiDelimStr+';',N+1)-N-1) AS GroupFruit

    INTO #FirstParse

    FROM #FruitTbl F

    CROSS JOIN dbo.Tally T

    Where T.N < LEN(';'+MultiDelimStr+';')

    AND SUBSTRING(';'+MultiDelimStr+';',N,1) = ';'

    --SELECT * FROM #FirstParse

    SELECT FruitID, GroupID

    ,SUBSTRING(','+GroupFruit+',',N+1,CHARINDEX(',',','+GroupFruit+',',N+1)-N-1) AS SoloFruit

    INTO #SecondParse

    FROM #FirstParse F

    CROSS JOIN dbo.Tally T

    Where T.N < LEN(','+GroupFruit+',')

    AND SUBSTRING(','+GroupFruit+',',N,1) = ','

    SELECT * FROM #SecondParse

    To get the result set (just showing 101 because this is already long enough):

    FruitIDGroupIDSoloFruit

    1011 Orange

    1011 Apple

    1012 Orange

    1012 Grape

    1012 Banana

    1013 Apple

    1013 Kiwi

    1013 Grape

    Now how do I put it back together and achieve the desired result set without multiple IF statements and multiple sets of subqueries or a loop (cursor/while)? Or is there a better way than splitting it twice? I know I am missing something that I fear I have read before, but I just can't remember it :crazy: XML?

    Thank you very much for your time and advice in advance.:-)

  • I'm not sure I understand all your requirements.

    Why ID = 101 has 3 combinations? There are 4 fruits there...

    Anyway this is what I could come up with. It could be a starter.

    IF OBJECT_ID('Tempdb..#TmpTbl') IS NOT NULL DROP TABLE #TmpTbl

    CREATE TABLE #TmpTbl (TblID INT PRIMARY KEY, MultiDelimStr VARCHAR(255))

    INSERT #TmpTbl ( TblID, MultiDelimStr )

    SELECT 101, 'Orange,Apple;Orange,Grape,Banana;Apple,Kiwi,Grape'

    UNION

    SELECT 202, 'Grape,Apple;Orange,Grape,Banana;Peach,Kiwi,Grape'

    UNION

    SELECT 303, 'Orange;Peach,Grape,Banana;Apple,Kiwi;Tangerine,Grapefruit'

    ;WITH Pass1 AS (

    SELECT TblId, C.Value

    FROM #TmpTbl AS A

    CROSS APPLY dbo.fSplit(MultiDelimStr, ';') AS B

    CROSS APPLY dbo.fSplit(B.Value, ',') AS C

    ),

    Pass2 AS (

    SELECT *

    FROM (

    SELECT DISTINCT *

    FROM Pass1

    ) AS A

    ),

    Ids AS (

    SELECT DISTINCT TblId

    FROM #TmpTbl

    )

    SELECT A.TblId, B.*

    FROM Pass2 AS A

    CROSS APPLY (

    SELECT CStr = A.Value + (

    SELECT ',' + Value AS [text()]

    FROM Pass2 AS P1

    WHERE P1.TblId = A.TblId

    AND P1.Value <> A.Value

    ORDER BY Value

    FOR XML PATH('')

    )

    )AS B

    This code uses a split function by Jeff Moden that can be found here: http://www.sqlservercentral.com/articles/T-SQL/62867/

    I'm including the function here:

    CREATE FUNCTION [dbo].[fSplit]

    (

    @Parameter VARCHAR(8000),

    @SplitOn char(1)

    )

    RETURNS @Elements TABLE

    (

    ID INT identity(1,1),

    Value VARCHAR(8000)

    )

    AS

    BEGIN

    --===== Add start and end commas to the Parameter so we can handle

    -- single elements

    SET @Parameter = @splitOn + @Parameter + @SplitOn

    --===== Join the Tally table to the string at the character level and

    -- when we find a comma, insert what's between that command and

    -- the next comma into the Elements table

    INSERT INTO @Elements (Value)

    SELECT SUBSTRING(@Parameter,N+1,CHARINDEX(@splitOn,@Parameter,N+1)-N-1)

    FROM dbo.Tally

    WHERE N < LEN(@Parameter)

    AND SUBSTRING(@Parameter,N,1) = @splitOn --Notice how we find the comma

    RETURN

    END

    I'm sure this is not what you're after...

    Good luck anyway

    -- Gianluca Sartori

  • Don't forget to create the Tally table from the article code if you're using the split function!

    Good luck with your query!

    -- Gianluca Sartori

  • I'm not sure I understand all your requirements.

    Why ID = 101 has 3 combinations? There are 4 fruits there...

    I am not sure I understand your question. ID 101 should have 10 combinations.

    Group1 has 2fruits. Group2 has 3 fruits. Group3 has 3 fruits. Group1 shares 1 fruit with Group2 and 1 different fruit with Group3. Group2 shares 1 fruit with Group3. Since Apple, Orange, Apple is not allowed, you can't count the number of items per group and the number of groups and get your total number of combinations using simple math. You have to know the repeats. This leaves the 10 combinations I list above in the original post.

    Thank you very much for the function and CTEs, I knew that I had seen something like that before. I will test against what I have and let you know if it does indeed answer my question.

  • Gianluca,

    Your solution, while helpful, does not return the desired result set.

    I think I see the confusion in my explanation of the problem.

    The problem is to come up with all of the unique GROUP combinations.

    The result set must have one fruit from Group1 and one fruit from Group2 ... 1 fruit from GroupN.

    So if the string field has 1 ';' then there are two groups; Group1 and Group2 (left and right of the ';'). The output should be one fruit from Group1 plus a ',' plus one fruit from Group2. More specifically, all the possible single-fruit-per-group combinations that keep Group1 fruits on the left and Group2 fruits on the right. With no fruit simultaneously in Group1 and Group2 spots during output.

    So if the string field has 2 ';' then there are three groups; Group1, Group2, Group3. Group1's fruits are to the left of the first ';' and Group3's are to the right of the last ';' and Group2's are in the the middle. Then re-concatenate them such that all the possible single-fruit-per-group combinations that keep Group1 fruits on the left and Group2 fruits in the middle and Group3 fruits on the right. With no fruit simultaneously in Group1, Group2 and/or Group3 spots during output.

    Etc.

    In my original post I list out all the valid combinations for output. That is the format that is desired. I hope this helps clear things up and expedites aid.

    Thank you all again for taking a look at this.

  • I must say I'm quite disappointed I could not solve this problem in a simple way.

    Maybe It's something beyond my skills.

    Anyway this is the best I could put together:

    IF OBJECT_ID('Tempdb..#TmpTbl') IS NOT NULL DROP TABLE #TmpTbl

    CREATE TABLE #TmpTbl (TblID INT PRIMARY KEY, MultiDelimStr VARCHAR(255))

    INSERT #TmpTbl ( TblID, MultiDelimStr )

    SELECT 101, 'Orange,Apple;Orange,Grape,Banana;Apple,Kiwi,Grape'

    UNION

    SELECT 202, 'Grape,Apple;Orange,Grape,Banana;Peach,Kiwi,Grape'

    UNION

    SELECT 303, 'Orange;Peach,Grape,Banana;Apple,Kiwi;Tangerine,Grapefruit'

    ;WITH Splits AS (

    SELECT TblId, GRP_ID = B.Id, C.Value AS Fruit, C.Id AS Fruit_id, NumGroups = MAX(B.Id) OVER(PARTITION BY TblId)

    FROM #TmpTbl AS A

    CROSS APPLY dbo.fSplit(MultiDelimStr, ';') AS B

    CROSS APPLY dbo.fSplit(B.Value, ',') AS C

    ),

    ThreeRows AS (

    SELECT N

    FROM Tally

    WHERE N <= 3

    ),

    FourRows AS (

    SELECT N

    FROM Tally

    WHERE N <= 4

    ),

    CrossThree AS (

    SELECT A.N AS [1], B.N AS [2], C.N AS [3]

    FROM ThreeRows AS A

    CROSS JOIN ThreeRows AS B

    CROSS JOIN ThreeRows AS C

    ),

    CrossFour AS (

    SELECT A.N AS [1], B.N AS [2], C.N AS [3], D.N AS [4]

    FROM FourRows AS A

    CROSS JOIN ThreeRows AS B

    CROSS JOIN ThreeRows AS C

    CROSS JOIN ThreeRows AS D

    )

    SELECT DISTINCT B.TblId, B.Fruit + ',' + C.Fruit + ',' + D.Fruit

    FROM CrossThree AS A

    INNER JOIN Splits AS B

    ON B.GRP_ID = 1

    AND B.Fruit_ID = [1]

    INNER JOIN Splits AS C

    ON C.GRP_ID = 2

    AND C.TblId = B.TblId

    AND C.Fruit_ID = [2]

    AND C.Fruit <> B.Fruit

    INNER JOIN Splits AS D

    ON D.GRP_ID = 3

    AND D.TblId = C.TblId

    AND D.Fruit_ID = [3]

    AND D.Fruit <> B.Fruit

    AND D.Fruit <> C.Fruit

    WHERE B.NumGroups = 3

    UNION ALL

    SELECT DISTINCT B.TblId, B.Fruit + ',' + C.Fruit + ',' + D.Fruit + ',' + E.Fruit

    FROM CrossFour AS A

    INNER JOIN Splits AS B

    ON B.GRP_ID = 1

    AND B.Fruit_ID = [1]

    INNER JOIN Splits AS C

    ON C.GRP_ID = 2

    AND C.TblId = B.TblId

    AND C.Fruit_ID = [2]

    AND C.Fruit <> B.Fruit

    INNER JOIN Splits AS D

    ON D.GRP_ID = 3

    AND D.TblId = C.TblId

    AND D.Fruit_ID = [3]

    AND D.Fruit <> B.Fruit

    AND D.Fruit <> C.Fruit

    INNER JOIN Splits AS E

    ON E.GRP_ID = 4

    AND E.TblId = D.TblId

    AND E.Fruit_ID = [4]

    AND E.Fruit <> B.Fruit

    AND E.Fruit <> C.Fruit

    AND E.Fruit <> D.Fruit

    WHERE B.NumGroups = 4

    Basically the code builds two work tables (CrossThree and CrossFour) with "N" columns, holding all N^N possible combinations of values between 1 and "N".

    Once the work tables are in place, I join them back to the splitted strings, choosing the right worktable looking at the number of groups.

    The main thing I don't like about this code is that it relies on fixed numbers of groups, so that it should be generated dynamically after a first pass on the input data to gather the minimum/maximum number of groups.

    I think this problem could be solved much better with a CLR aggregate, but it's a technique I don't master.

    I hope someone can help with something better than this.

    Gianluca

    -- Gianluca Sartori

  • Your solution is similar to mine with more joins than I believe to be efficient, but still effective.

    I am also hoping someone else can provide a cleaner, simpler, more efficient way to solve this challenge.

    I do appreciate the time you put into this; thanks! ๐Ÿ˜€

  • I was wondering if you had control over the schema and could change it to have all the data broken out into different tables? Gianluca did that with his CTE, and with that something like this works:

    ;WITH Splits AS (

    SELECT TblId, GRP_ID = B.Id, C.Value AS Fruit

    FROM #TmpTbl AS A

    CROSS APPLY dbo.fSplit(MultiDelimStr, ';') AS B

    CROSS APPLY dbo.fSplit(B.Value, ',') AS C

    )

    SELECT one.tblID, one.Fruit + ',' + two.Fruit + ISNULL(',' + three.Fruit, '') + ISNULL(',' + four.Fruit, '') + ISNULL(',' + five.Fruit, '')

    FROM Splits one

    LEFT JOIN Splits two on (one.tblID = two.tblID AND two.GRP_ID = 2)

    LEFT JOIN Splits three on (one.tblID = three.tblID AND three.GRP_ID = 3)

    LEFT JOIN Splits four on (one.tblID = four.tblID AND four.GRP_ID = 4)

    LEFT JOIN Splits five on (one.tblID = five.tblID AND five.GRP_ID = 5)

    WHERE ISNULL(one.Fruit,'') != ISNULL(two.Fruit,'*')

    and ISNULL(one.Fruit,'') != ISNULL(three.Fruit,'*')

    and ISNULL(one.Fruit,'') != ISNULL(four.Fruit,'*')

    and ISNULL(one.Fruit,'') != ISNULL(five.Fruit,'*')

    and ISNULL(two.Fruit,'') != ISNULL(three.Fruit,'*')

    and ISNULL(two.Fruit,'') != ISNULL(four.Fruit,'*')

    and ISNULL(two.Fruit,'') != ISNULL(five.Fruit,'*')

    and ISNULL(three.Fruit,'') != ISNULL(four.Fruit,'*')

    and ISNULL(three.Fruit,'') != ISNULL(five.Fruit,'*')

    and ISNULL(four.Fruit,'') != ISNULL(five.Fruit,'*')

    AND one.GRP_ID = 1

    It's basically just a table join making sure you don't get duplicates back. Ugly, but it worked with the sample data.

    Chad

  • I was wondering if you had control over the schema and could change it to have all the data broken out into different tables?

    Doesn't every DBA/D want control over that? LOL And no, I do not.

    Ugly, but it worked with the sample data.

    Yeah, but do you think it is possible to do this more "Swan" and less "Duckling?" Is there a better way to start? (other than changing the schema, of course;-))

    What is the performance hit of joining the same table 5 times going to be when I try to do 100,000 of these at once?

    Thank you for your time and help.

  • Well... not any answers, but some more questions and thoughts that might spark a new idea:

    When you query out for these, you are doing it based on the TBLID, right? You aren't looking for everything from everywhere each time? With that in mind, you could target those rows with a where clause in the CTE and that would make a huge difference with that column indexed. I wouldn't think that would be too bad at all.

    What do the insert/updates against this table look like - are they frequent and constant? I hate recommending a trigger because of the overhead they represent, but if inserts, updates and deletes are infrequent, you could use a trigger to mirror the structure in 5 seperate tables and with TBLID indexed the performance shouldn't be too bad. Or, you could just prebuild all the information on the fly from the trigger in the first place.

    I know you don't have control over the schema, but if you could take some metrics to someone (I'm just making this up, but "If we change the schema we'll go from 5 minute queries to sub-second queries" or whatever it turns out to be), would they consider making some changes? If you use some sample data and an environment similar to what you have in production, can you see what difference a new schema might make?

    Do you have enough control over the schema to change the content of the string? I'm not the best at XML, but if the string was in an XML format, there might (I don't know) be some new opportunities that don't involve all the joins and loops and just leverage the XML.

    What is the consuming target for the data? Is it a report, or is this an input to another algorithm? SQL doesn't have a full complement of string tools, would it be faster to offload some of the work to the next layer?

    Do you need real-time access to the data? If you prebuilt a report table on a semi-regular basis so that all the crunching was done once and all the reporting/consuming was done off a slightly out-of-date copy, would it be satisfactory?

    And I guess the other question is do you have an environment to test a real-sized load to see what it would do?

    Thanks,

    Chad

  • Thank you Chad. I just got pulled in another direction while reading your reply. It might be a while before I can answer all those questions.

  • Oh no - don't answer all the questions. Just take a look and see if anything jumps out at you. I'm thinking the first one might be the best - if you are only ever querying for specific TBLIDs, indexing that and adding it to the where will probably make just about anything fast enough to be ok... well, depending on your requirements. The thoughts I wrote down got progressively worse as I kept thinking, but they were ideas that might work, depending on the situation you are in, and since I thought of them. I felt compelled to write them down. That doesn't mean you are compelled to listen to them ๐Ÿ˜›

    Thanks,

    Chad

  • Gianluca Sartori (7/12/2010)


    I think this problem could be solved much better with a CLR aggregate, but it's a technique I don't master.

    A CLR aggregate wouldn't be the right choice because an aggregate only returns one row from multiple rows of input. What we need to do here is return multiple rows (the combinations) from a single row input (the multi-delimited string). For that, we need a streaming CLR table-valued function.

    Using the table and sample data kindly provided by pmcpherson, the full solution becomes:

    SELECT TT.TblID, GC.combination

    FROM #TmpTbl TT

    CROSS

    APPLY dbo.GetCombinations(TT.MultiDelimStr) GC;

    It is extremely fast and quite neat. The source code and binary will follow in my next post.

    Paul

  • 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;

    }

    }

  • T-SQL assembly and function creation:

    Assembly:

    CREATE ASSEMBLY [StringCombo] AUTHORIZATION [dbo]

    FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C010300E5AA3D4C0000000000000000E00002210B010800000E000000060000000000009E2C0000002000000040000000004000002000000002000004000000000000000400000000000000008000000002000000000000030040850000100000100000000010000010000000000000100000000000000000000000482C000053000000004000001803000000000000000000000000000000000000006000000C000000A42B00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000A40C000000200000000E000000020000000000000000000000000000200000602E7273726300000018030000004000000004000000100000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001400000000000000000000000000004000004200000000000000000000000000000000802C0000000000004800000002000500B0210000F409000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001330050066000000010000110F00281300000A2C07168D180000012A731400000A0A0F00281500000A178D190000010D09161F3B9D09176F1600000A0B160C2B230607089A178D1900000113041104161F2C9D1104176F1600000A6F1700000A0817580C08078E6932D7160628030000062A00001330040024000000020000110274180000010A0616066F1800000A17596F1900000A0A0306731A00000A81030000012A1B3004009700000003000011731B00000A0A02036F1C00000A330D067E1D00000A6F1E00000A062A03026F1F00000A0D1613042B650911049A0B0217580328030000066F2000000A13052B2F1205282100000A0C08071F2C8C19000001282200000A6F2300000A2D120607720100007008282400000A6F1E00000A1205282500000A2DC8DE0E1205FE160300001B6F2600000ADC1104175813041104098E693294062A000110000002003E003C7A000E000000001E02282700000A2A42534A4201000100000000000C00000076322E302E35303732370000000005006C000000F8020000237E0000640300001004000023537472696E6773000000007407000008000000235553007C0700001000000023475549440000008C0700006802000023426C6F620000000000000002000001471502080900000000FA253300160000010000001C000000020000000400000005000000270000000F0000000300000003000000010000000200000000000A0001000000000006003F0038000600590046000A00860071000600C300A8000A000101E600060042012301060071015F01060088015F010600A5015F010600C4015F010600DD015F010600F6015F01060011025F0106002C025F01060045022301060059022301060067025F01060080025F010600B0029D024F00C40200000600F302D30206001303D3020A003D03E60006005D03380006006E0338000600730338001300BE0300000600FC0338000000000001000000000001000100010010001A000000050001000100502000000000960090000A000100C420000000009600A00011000200F420000000009100CA0019000400A821000000008618DA002800060000000100E000000001001301020002001701000001004F010000020055012900DA0028003100DA0028003900DA005E004100DA005E004900DA005E005100DA005E005900DA005E006100DA005E006900DA005E007100DA005E007900DA0063008100DA005E008900DA005E009100DA005E009900DA006800A900DA006E00B100DA002800B900DA002800190052034D010C00DA002800190064035801C10086035C010C008C036501C10090037B01C1009B037F011900DA005E001400DA0028000C00A5037B01C100AF038F0114008C0365010C00B50392011400C90398011C00D703A701C100E303AC01C100EA03B201C100E303B7011C00F3034D01E100080428000900DA00280020009300730024000B002C002E004300E7012E002300E1012E002B00E1012E003300E1012E003B00D0012E001B00D0012E004B00E1012E005B00E1012E006300FF012E00730029022E007B0036022E0083003F022E008B0048026B018501BE0151018901A1010480000001000000000000000000000000003103000002000000000000000000000001002F000000000002000000000000000000000001006500000000000000003C4D6F64756C653E00537472696E67436F6D626F2E646C6C0055736572446566696E656446756E6374696F6E73006D73636F726C69620053797374656D004F626A6563740053797374656D2E436F6C6C656374696F6E730049456E756D657261626C650053797374656D2E446174610053797374656D2E446174612E53716C54797065730053716C537472696E6700476574436F6D62696E6174696F6E730046696C6C526F770053797374656D2E436F6C6C656374696F6E732E47656E65726963004C697374603100726563757273697665417070656E64002E63746F7200696E707574004D6963726F736F66742E53716C5365727665722E5365727665720053716C4661636574417474726962757465006F626A00636F6D62696E6174696F6E0053797374656D2E52756E74696D652E496E7465726F705365727669636573004F7574417474726962757465006C6576656C00696E7075744C6973740053797374656D2E5265666C656374696F6E00417373656D626C795469746C6541747472696275746500417373656D626C794465736372697074696F6E41747472696275746500417373656D626C79436F6E66696775726174696F6E41747472696275746500417373656D626C79436F6D70616E7941747472696275746500417373656D626C7950726F6475637441747472696275746500417373656D626C79436F7079726967687441747472696275746500417373656D626C7954726164656D61726B41747472696275746500417373656D626C7943756C7475726541747472696275746500436F6D56697369626C65417474726962757465004775696441747472696275746500417373656D626C7956657273696F6E41747472696275746500417373656D626C7946696C6556657273696F6E4174747269627574650053797374656D2E446961676E6F73746963730044656275676761626C6541747472696275746500446562756767696E674D6F6465730053797374656D2E52756E74696D652E436F6D70696C6572536572766963657300436F6D70696C6174696F6E52656C61786174696F6E734174747269627574650052756E74696D65436F6D7061746962696C69747941747472696275746500537472696E67436F6D626F0053716C46756E6374696F6E417474726962757465006765745F49734E756C6C00537472696E67006765745F56616C7565004368617200537472696E6753706C69744F7074696F6E730053706C697400416464006765745F4C656E67746800537562737472696E67006765745F436F756E7400456D707479006765745F4974656D00456E756D657261746F7200476574456E756D657261746F72006765745F43757272656E7400436F6E63617400436F6E7461696E73004D6F76654E6578740049446973706F7361626C6500446973706F73650000032C0000000000412656320686FE4198E338DDF3A796A60008B77A5C561934E0890600011209110D070002011C10110D0E0002151211010E08151211011D0E0320000131010003005408074D617853697A650001000054020A49734E756C6C61626C650054020D497346697865644C656E67746800042001010E0420010102052001011151042001010880D8010003005455794D6963726F736F66742E53716C5365727665722E5365727665722E446174614163636573734B696E642C2053797374656D2E446174612C2056657273696F6E3D322E302E302E302C2043756C747572653D6E65757472616C2C205075626C69634B6579546F6B656E3D623737613563353631393334653038390A4461746141636365737300000000540E1146696C6C526F774D6574686F644E616D650746696C6C526F77540E0F5461626C65446566696E6974696F6E1A636F6D62696E6174696F6E204E564152434841522834303030290320000206151211011D0E0320000E0820021D0E1D0311690520010113000F0705151211011D0E1D0E081D031D03032000080520020E08080307010E05151211010E02060E05200113000808200015116D0113000515116D010E04200013000500020E1C1C042001020E0600030E0E0E0E110706151211010E0E0E1D0E0815116D010E1001000B537472696E67436F6D626F000005010000000017010012436F7079726967687420C2A920203230313000002901002430303264663264382D663839392D343162392D386632632D36616335653161613832373400000C010007312E302E302E3000000801000200000000000801000800000000001E01000100540216577261704E6F6E457863657074696F6E5468726F7773010000000000E5AA3D4C000000000200000088000000C02B0000C00D0000525344537BB1CA208BBDE24C8EC97D6E38B8E62203000000433A5C446F63756D656E747320616E642053657474696E67735C5061756C5C6D7920646F63756D656E74735C76697375616C2073747564696F20323031305C50726F6A656374735C537472696E67436F6D626F5C6F626A5C52656C656173655C537472696E67436F6D626F2E70646200702C000000000000000000008E2C0000002000000000000000000000000000000000000000000000802C000000000000000000000000000000005F436F72446C6C4D61696E006D73636F7265652E646C6C0000000000FF250020400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000001800008000000000000000000000000000000100010000003000008000000000000000000000000000000100000000004800000058400000C00200000000000000000000C00234000000560053005F00560045005200530049004F004E005F0049004E0046004F0000000000BD04EFFE00000100000001000000000000000100000000003F000000000000000400000002000000000000000000000000000000440000000100560061007200460069006C00650049006E0066006F00000000002400040000005400720061006E0073006C006100740069006F006E00000000000000B00420020000010053007400720069006E006700460069006C00650049006E0066006F000000FC010000010030003000300030003000340062003000000040000C000100460069006C0065004400650073006300720069007000740069006F006E000000000053007400720069006E00670043006F006D0062006F000000300008000100460069006C006500560065007200730069006F006E000000000031002E0030002E0030002E003000000040001000010049006E007400650072006E0061006C004E0061006D006500000053007400720069006E00670043006F006D0062006F002E0064006C006C0000004800120001004C006500670061006C0043006F007000790072006900670068007400000043006F0070007900720069006700680074002000A90020002000320030003100300000004800100001004F0072006900670069006E0061006C00460069006C0065006E0061006D006500000053007400720069006E00670043006F006D0062006F002E0064006C006C00000038000C000100500072006F0064007500630074004E0061006D0065000000000053007400720069006E00670043006F006D0062006F000000340008000100500072006F006400750063007400560065007200730069006F006E00000031002E0030002E0030002E003000000038000800010041007300730065006D0062006C0079002000560065007200730069006F006E00000031002E0030002E0030002E003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000C000000A03C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

    WITH PERMISSION_SET = SAFE;

    Function:

    CREATE FUNCTION [dbo].[GetCombinations]

    (

    @input NVARCHAR(256)

    )

    RETURNS TABLE

    (

    combination NVARCHAR(4000) NULL

    )

    WITH EXECUTE AS CALLER

    AS EXTERNAL NAME [StringCombo].[UserDefinedFunctions].[GetCombinations];

Viewing 15 posts - 1 through 15 (of 17 total)

You must be logged in to reply to this topic. Login to reply