patternsqlMajor
SQL query for combinations without repetition
Viewed 0 times
withoutcombinationssqlqueryforrepetition
Problem
I need a function that can generate all possible combinations of a given set of n values. For each combination, the function should also generate all combinations of length k, where k ranges from 1 to n.
For example, if the input is a table with three values in one column, then the function should generate all possible combinations of the three values, as well as all possible combinations of length 1, 2, and 3.
Example:
Input: table with values in one column in multiple rows
Output#1: table with values concatenated in one column
For example, if the input is a table with three values in one column, then the function should generate all possible combinations of the three values, as well as all possible combinations of length 1, 2, and 3.
Example:
Input: table with values in one column in multiple rows
Value (nvarchar(500))
------
Ann
John
MarkOutput#1: table with values concatenated in one column
Ann
John
Mark
Ann,John
John,Mark
Ann,Mark
Ann,John,MarkSolution
For relatively small values of
T-SQL Solution
Sample data:
Solution:
Output sample:
Execution plan:
It takes 41 seconds to write the 1,048,576 combinations to a variable on my laptop. With forced parallelism, I was able to drop the execution time at
If you need a Numbers table, this is a quick way to produce one:
SQLCLR solution
A much more efficient implementation is possible in SQLCLR (SQL Server 2005 onward):
```
CREATE ASSEMBLY [Demo]
AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0103000705BC500000000000000000E00002210B010800001000000006000000000000EE2E00000020000000400000000040000020000000020000040000000000000004000000000000000080000000020000000000000300408500001000001000000000100000100000000000001000000000000000000000009C2E00004F000000004000009802000000000000000000000000000000000000006000000C000000042E00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000F40E0000002000000010000000020000000000000000000000000000200000602E7273726300000098020000004000000004000000120000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001600000000000000000000000000004000004200000000000000000000000000000000D02E0000000000004800000002000500B82200004C0B00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000133002003C00000001000011280E00000A6F0F00000A027B030000043315027B020000041FFE330B02167D02000004020A2B0716730C0000060A06027B050000047D04000004062A1E0228050000062A133005006101000002000011027B020000040C0845020000000500000024010000384501000002157D0200000402027B04000004178D0F0000010D09161F2C9D096F1000000A7D0600000402027B060000048E698D110000017D0700000402230000000000000040027B060000048E696C281100000A6917597D08000004160A2B1D027B0700000406230000000000000040066C281100000A699E0617580A06027B070000048E6932D802177D0A00000438A4000000027E1200000A7D09000004160B2B3D027B0A000004027B0700000407945F027B070000040794332002257B09000004027B06000004079A1F2C8C0F000001281300000A7D090000040717580B07027B070000048E692F10027B0A000004027B0700000407942FA802027B0900000416027B09000
n (20 in this example), you can use a method that exploits the fact that the natural integers are combinations of bits.T-SQL Solution
Sample data:
DECLARE @Sample AS TABLE
(
item_id tinyint IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
item nvarchar(500) NOT NULL,
bit_value AS
CONVERT
(
integer,
POWER(2, item_id - 1)
)
PERSISTED UNIQUE CLUSTERED
);
INSERT @Sample
(item)
VALUES
(N'Ann'),
(N'Bob'),
(N'Charles'),
(N'Darren'),
(N'Eric'),
(N'Fred'),
(N'George'),
(N'Harry'),
(N'Ian'),
(N'John'),
(N'Keith'),
(N'Larry'),
(N'Mark'),
(N'Nathan'),
(N'Owen'),
(N'Paul'),
(N'Quentin'),
(N'Ryan'),
(N'Steve'),
(N'Terry');Solution:
-- Maximum integer we need
-- for all combinations of 'n' bits
DECLARE
@max integer =
POWER(2,
(
SELECT COUNT(*)
FROM @Sample AS s
)
) - 1;
SELECT
combination =
STUFF
(
(
-- Choose items where the bit is set
-- and concatenate all matches
SELECT ',' + s.item
FROM @Sample AS s
WHERE
n.n & s.bit_value = s.bit_value
ORDER BY
s.bit_value
FOR XML
PATH (''),
TYPE
).value('(./text())[1]', 'varchar(8000)'), 1, 1, ''
)
-- A standard numbers table
-- (single column, integers from 1 to 1048576, indexed)
FROM dbo.Numbers AS N
WHERE
N.n BETWEEN 1 AND @max;Output sample:
╔════════════════════════╗
║ combination ║
╠════════════════════════╣
║ Ann ║
║ Bob ║
║ Ann,Bob ║
║ Charles ║
║ Ann,Charles ║
║ Bob,Charles ║
║ Ann,Bob,Charles ║
║ Darren ║
║ Ann,Darren ║
║ Bob,Darren ║
║ Ann,Bob,Darren ║
║ Charles,Darren ║
║ Ann,Charles,Darren ║
║ Bob,Charles,Darren ║
║ Ann,Bob,Charles,Darren ║
║ ... ║
╚════════════════════════╝Execution plan:
It takes 41 seconds to write the 1,048,576 combinations to a variable on my laptop. With forced parallelism, I was able to drop the execution time at
DOP 8 to 13 seconds.If you need a Numbers table, this is a quick way to produce one:
SELECT TOP (1048576)
n = ISNULL(CONVERT(integer, ROW_NUMBER() OVER (ORDER BY (SELECT NULL))), 0)
INTO dbo.Numbers
FROM sys.columns AS c
CROSS JOIN sys.columns AS c2
CROSS JOIN sys.columns AS c3;
CREATE UNIQUE CLUSTERED INDEX cuq
ON dbo.Numbers (n)
WITH (MAXDOP = 1, SORT_IN_TEMPDB = ON);SQLCLR solution
A much more efficient implementation is possible in SQLCLR (SQL Server 2005 onward):
```
CREATE ASSEMBLY [Demo]
AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0103000705BC500000000000000000E00002210B010800001000000006000000000000EE2E00000020000000400000000040000020000000020000040000000000000004000000000000000080000000020000000000000300408500001000001000000000100000100000000000001000000000000000000000009C2E00004F000000004000009802000000000000000000000000000000000000006000000C000000042E00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000F40E0000002000000010000000020000000000000000000000000000200000602E7273726300000098020000004000000004000000120000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001600000000000000000000000000004000004200000000000000000000000000000000D02E0000000000004800000002000500B82200004C0B00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000133002003C00000001000011280E00000A6F0F00000A027B030000043315027B020000041FFE330B02167D02000004020A2B0716730C0000060A06027B050000047D04000004062A1E0228050000062A133005006101000002000011027B020000040C0845020000000500000024010000384501000002157D0200000402027B04000004178D0F0000010D09161F2C9D096F1000000A7D0600000402027B060000048E698D110000017D0700000402230000000000000040027B060000048E696C281100000A6917597D08000004160A2B1D027B0700000406230000000000000040066C281100000A699E0617580A06027B070000048E6932D802177D0A00000438A4000000027E1200000A7D09000004160B2B3D027B0A000004027B0700000407945F027B070000040794332002257B09000004027B06000004079A1F2C8C0F000001281300000A7D090000040717580B07027B070000048E692F10027B0A000004027B0700000407942FA802027B0900000416027B09000
Code Snippets
DECLARE @Sample AS TABLE
(
item_id tinyint IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
item nvarchar(500) NOT NULL,
bit_value AS
CONVERT
(
integer,
POWER(2, item_id - 1)
)
PERSISTED UNIQUE CLUSTERED
);
INSERT @Sample
(item)
VALUES
(N'Ann'),
(N'Bob'),
(N'Charles'),
(N'Darren'),
(N'Eric'),
(N'Fred'),
(N'George'),
(N'Harry'),
(N'Ian'),
(N'John'),
(N'Keith'),
(N'Larry'),
(N'Mark'),
(N'Nathan'),
(N'Owen'),
(N'Paul'),
(N'Quentin'),
(N'Ryan'),
(N'Steve'),
(N'Terry');-- Maximum integer we need
-- for all combinations of 'n' bits
DECLARE
@max integer =
POWER(2,
(
SELECT COUNT(*)
FROM @Sample AS s
)
) - 1;
SELECT
combination =
STUFF
(
(
-- Choose items where the bit is set
-- and concatenate all matches
SELECT ',' + s.item
FROM @Sample AS s
WHERE
n.n & s.bit_value = s.bit_value
ORDER BY
s.bit_value
FOR XML
PATH (''),
TYPE
).value('(./text())[1]', 'varchar(8000)'), 1, 1, ''
)
-- A standard numbers table
-- (single column, integers from 1 to 1048576, indexed)
FROM dbo.Numbers AS N
WHERE
N.n BETWEEN 1 AND @max;╔════════════════════════╗
║ combination ║
╠════════════════════════╣
║ Ann ║
║ Bob ║
║ Ann,Bob ║
║ Charles ║
║ Ann,Charles ║
║ Bob,Charles ║
║ Ann,Bob,Charles ║
║ Darren ║
║ Ann,Darren ║
║ Bob,Darren ║
║ Ann,Bob,Darren ║
║ Charles,Darren ║
║ Ann,Charles,Darren ║
║ Bob,Charles,Darren ║
║ Ann,Bob,Charles,Darren ║
║ ... ║
╚════════════════════════╝SELECT TOP (1048576)
n = ISNULL(CONVERT(integer, ROW_NUMBER() OVER (ORDER BY (SELECT NULL))), 0)
INTO dbo.Numbers
FROM sys.columns AS c
CROSS JOIN sys.columns AS c2
CROSS JOIN sys.columns AS c3;
CREATE UNIQUE CLUSTERED INDEX cuq
ON dbo.Numbers (n)
WITH (MAXDOP = 1, SORT_IN_TEMPDB = ON);CREATE ASSEMBLY [Demo]
AUTHORIZATION [dbo]
FROM 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000800000000E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000504500004C0103000705BC500000000000000000E00002210B010800001000000006000000000000EE2E00000020000000400000000040000020000000020000040000000000000004000000000000000080000000020000000000000300408500001000001000000000100000100000000000001000000000000000000000009C2E00004F000000004000009802000000000000000000000000000000000000006000000C000000042E00001C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000080000000000000000000000082000004800000000000000000000002E74657874000000F40E0000002000000010000000020000000000000000000000000000200000602E7273726300000098020000004000000004000000120000000000000000000000000000400000402E72656C6F6300000C0000000060000000020000001600000000000000000000000000004000004200000000000000000000000000000000D02E0000000000004800000002000500B82200004C0B00000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000133002003C00000001000011280E00000A6F0F00000A027B030000043315027B020000041FFE330B02167D02000004020A2B0716730C0000060A06027B050000047D04000004062A1E0228050000062A133005006101000002000011027B020000040C0845020000000500000024010000384501000002157D0200000402027B04000004178D0F0000010D09161F2C9D096F1000000A7D0600000402027B060000048E698D110000017D0700000402230000000000000040027B060000048E696C281100000A6917597D08000004160A2B1D027B0700000406230000000000000040066C281100000A699E0617580A06027B070000048E6932D802177D0A00000438A4000000027E1200000A7D09000004160B2B3D027B0A000004027B0700000407945F027B070000040794332002257B09000004027B06000004079A1F2C8C0F000001281300000A7D090000040717580B07027B070000048E692F10027B0A000004027B0700000407942FA802027B0900000416027B090000046F1400000A17596F1500000A7D0100000402177D02000004172A02157D0200000402257B0A00000417587D0A000004027B0A000004027B080000043E4BFFFFFF162A1E027B010000042A1A731600000A7A1330000001000000030000112A1E027B010000042A7A02281700000A02037D0200000402280E00000A6F0F00000A7D030000042A1330020011000000010000111FFE730C0000060A06027D05000004062AD60202176320555555555F5910000220333333335F02186320333333335F58100002021A6358200F0F0F0F5F20010101015A1F18632A2603027410000001512A1E02281700000A2A00000042534A4201000100000000000C00000076322E302E35303732370000000005006C00000088030000237E0000F4030000F404000023537472696E677300000000E80800000800000023555300F0080000100000002347554944000000000900004C02000023426C6F6200000000000000020000015717A20B0902000000FA2533001600000100000014000000030000000A0000000C0000000500000005000000180000000B00000003000000010000000200000002000000070000000200000001000000020000000100000000000A00010000000000060038003100060052003F000600BF00A0000600DF00CC001300F30000000600220102010600420102010A008C01710106Context
StackExchange Database Administrators Q#29661, answer score: 38
Revisions (0)
No revisions yet.