Combination Algorithm in T-SQL

  • So I'm looking for a slick way to do a query without a boatload of cursors and if statements. I have a large users table where the user can have up to 8 roles associated to each user. What I'm mining are the most popular role combinations.

    For example, take this sample dataset:

    Username Role

    --------- -----------

    jsmith user

    jsmith reporter

    tjones user

    tjones reporter

    sfield administrator

    sfield reporter

    mconner user

    kreynold administrator

    The aggregate would be:

    user/reporter: 2

    admin/reporter: 1

    user: 1

    admin: 1

    How is this best accomplished in tsql?

  • Check out pivot in BOLs.

    Once you've pivoted the data your resultset would look like

    user, perm1, perm2, perm3....

    Then it's only a matter of doing a group by all perms and counting the winners.

  • or another more manual way

    step one.

    Select username, MAX(CASE WHEN Permissions = 'user' THEN 'User' ELSE NULL END) As User, , MAX(CASE WHEN Permissions = 'reporter' THEN 'reporter' ELSE NULL END) As Reporter......... from ...... group by username

    Step 2, use step 1 as derived table and do your aggregates.

  • I was looking at pivot but if I pivot each role into a column that doesn't give me the permutations....

    So in my example if I pivot the result set would look like this:

    username----user-----reporter-----administrator

    tsmith-------1--------1------------null

    tjones-------1--------1------------null

    sfield--------null------1------------1

    mconnor-----1--------null----------null

    kreynold-----null------null----------1

    So how would I do the grouping to get all the role combinations from this?

    If I could pivot to get the following then I would be in business:

    username-----roles

    tsmith--------user,reporter

    tjones--------user,reporter

    etc...

  • Do a search for concatenation in the scripts sections and you'll find what you need for that.

    Now another problem you'll face is that you'll need to sort before you concatenate... a problem you would avoid with the pivot.

    Also remember that if you have 8 permission groups but only 2 set you get john smith, 1, 1, null, null.....

    If you group by all 8 columns you would effectively have only 1 permutation with a count(*) or whatever else you need. Once in the application you don't have to show the null columns.

  • Hi Chris,

    How about this:

    DECLARE @UserRole

    TABLE (

    row_id INTEGER IDENTITY PRIMARY KEY,

    [user_name] SYSNAME COLLATE LATIN1_GENERAL_CI_AS NOT NULL,

    role_name SYSNAME COLLATE LATIN1_GENERAL_CI_AS NOT NULL,

    UNIQUE ([user_name], role_name)

    );

    INSERT @UserRole ([user_name], role_name) VALUES (N'jsmith', N'user');

    INSERT @UserRole ([user_name], role_name) VALUES (N'jsmith', N'reporter');

    INSERT @UserRole ([user_name], role_name) VALUES (N'tjones', N'user');

    INSERT @UserRole ([user_name], role_name) VALUES (N'tjones', N'reporter');

    INSERT @UserRole ([user_name], role_name) VALUES (N'sfield', N'administrator');

    INSERT @UserRole ([user_name], role_name) VALUES (N'sfield', N'reporter');

    INSERT @UserRole ([user_name], role_name) VALUES (N'mconner', N'user');

    INSERT @UserRole ([user_name], role_name) VALUES (N'kreynold', N'administrator');

    SELECT Users.[user_name],

    Roles.combination

    FROM (

    -- Distinct users

    SELECT [user_name]

    FROM @UserRole UR1

    GROUP BY [user_name]

    )

    AS Users

    CROSS

    APPLY

    -- Apply the result of this table-valued function

    -- to each row from Users

    (

    -- Concatenate the roles, in a defined order

    SELECT N'/' + role_name

    FROM @UserRole UR2

    WHERE UR2.user_name = Users.user_name -- correlation

    ORDER BY role_name

    FOR XML PATH('')

    )

    AS Roles (combination);

    Output:

    user_name combination

    jsmith /reporter/user

    kreynold /administrator

    mconner /user

    sfield /administrator/reporter

    tjones /reporter/user

    I have provided sample data for anyone else that wants an easy way to investigate this problem 😉

    Paul

    edit: added output

Viewing 6 posts - 1 through 5 (of 5 total)

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