在 SQL Server 中生成排列的最优雅的方法
给定下表:
Index | Element
---------------
1 | A
2 | B
3 | C
4 | D
我们希望使用元素生成所有可能的排列(不重复)。 最终结果(跳过一些行)将如下所示:
Results
----------
ABCD
ABDC
ACBD
ACDB
ADAC
ADCA
...
DABC
DACB
DBCA
DBAC
DCAB
DCBA
(24 Rows)
你会怎么做?
Given a the following table:
Index | Element
---------------
1 | A
2 | B
3 | C
4 | D
We want to generate all the possible permutations (without repetitions) using the elements.
the final result (skipping some rows) will look like this:
Results
----------
ABCD
ABDC
ACBD
ACDB
ADAC
ADCA
...
DABC
DACB
DBCA
DBAC
DCAB
DCBA
(24 Rows)
How would you do it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
在发表了一些可能尖刻的评论之后,这个问题整个晚上都在我的脑海里盘旋,我最终想出了以下基于集合的方法。我相信它绝对符合“优雅”的标准,但我也认为它符合“有点愚蠢”的标准。你拨打电话。
首先,设置一些表:
例程如下:
总体思路是:将新元素(例如“B”)添加到任何字符串(例如“A”)时,要捕获所有排列,您将添加 B
到所有可能的位置(Ba,aB),从而产生一组新的字符串。然后迭代:向字符串中的每个位置添加一个新元素 (C)
(AB 变为 Cab、aCb、abC),对于所有字符串(Cba、bCa、baC),您就有了一组排列。迭代每个结果集
下一个角色,直到你用完角色......或资源。 10 个元素是 360 万种排列,使用上述算法大约为 48MB,14 个(唯一)元素将达到 870 亿种排列和 1.163 TB。
我确信它最终可能会被嵌入到 CTE 中,但最终这只是一个美化的循环。逻辑
这样就更清晰了,我不禁认为 CTE 执行计划将是一场噩梦。
After making some perhaps snarky comments, this problem stuck in my brain all evening, and I eventually came up with the following set-based approach. I believe it definitely qualifies as "elegant", but then I also think it qualifies as "kinda dumb". You make the call.
First, set up some tables:
Here's the routine:
The general idea is: when adding a new element (say "B") to any string (say, "A"), to catch all permutations you would add B
to all possible positions (Ba, aB), resulting in a new set of strings. Then iterate: Add a new element (C) to each position in a string
(AB becomes Cab, aCb, abC), for all strings (Cba, bCa, baC), and you have the set of permutations. Iterate over each result set with
the next character until you run out of characters... or resources. 10 elements is 3.6 million permutations, roughly 48MB with the above algorithm, and 14 (unique) elements would hit 87 billion permutations and 1.163 terabytes.
I'm sure it could eventually be wedged into a CTE, but in the end all that would be is a glorified loop. The logic
is clearer this way, and I can't help but think the CTE execution plan would be a nightmare.
不久前首次发布这里
但是,它最好用更好的语言(例如 C# 或 C++)来完成。
first posted a while ago here
However, it would be better to do it in a better language such as C# or C++.
只需使用 SQL,无需任何代码,如果您可以将另一列插入表中,您就可以做到这一点。显然,您需要为每个要排列的值建立一个连接表。
Just using SQL, without any code, you could do it if you can crowbar yourself another column into the table. Clearly you need to have one joined table for each of the values to be permuted.
我是否正确理解您构建了笛卡尔积 nxnxnxn,然后过滤掉不需要的东西?另一种方法是生成直到 n! 的所有数字!然后使用 阶乘数字系统 通过元素编码来映射它们。
Am I correctly understanding that you built Cartesian product n x n x n x n, and then filter out unwanted stuff? The alternative would be generating all the numbers up to n! and then using factorial number system to map them via element encoding.
比递归 CTE 更简单:
对于任意数量的元素,将其编写为脚本:
要生成此:
Simpler than a recursive CTE:
For an arbitrary number of elements, script it out:
To generate this:
此方法使用二进制掩码来选择正确的行:
我的原始帖子:
这是困扰您的问题之一。我喜欢我原来答案的简单性,但有一个问题,我仍在构建所有可能的解决方案,然后选择正确的解决方案。另一种尝试是通过仅构建正确的解决方案来提高此过程的效率,得到了这个答案。仅当字符串中不存在该字符时才将该字符添加到字符串中。 Patindex 似乎是 CTE 解决方案的完美伴侣。这里是。
我能够在 3 分 2 秒内构建全部 360 万个解决方案。希望这个解决方案不会因为它不是第一个而被错过。
This method uses a binary mask to select the correct rows:
My original post:
This is one of those problems that haunts you. I liked the simplicity of my original answer but there was this issue where I was still building all the possible solutions and then selecting the correct ones. One more try to make this process more efficient by only building the solutions that were correct yielded this answer. Add a character to the string only if that character didn't exist in the string. Patindex seemed like the perfect companion for a CTE solution. Here it is.
I was able to build all 3.6 million solutions in 3 minutes and 2 seconds. Hopefully this solution will not get missed just because it's not the first.
当前的解决方案使用递归 CTE。
Current solution using a recursive CTE.
假设您的表名为 Elements 并且有 4 行,则简单如下:
Assuming your table is named Elements and has 4 rows, this is as simple as:
我的 SQL 技能太生锈了,但我对类似的问题采取了不同的策略,并认为值得分享。
对于添加了 CROSS JOIN 的 3 个表,原则相同,
尽管它在联合中需要 6 个交叉连接集。
Way too much rust on my SQL skills, but i took a different tack for a similar problem and thought it worth sharing.
Same principle for 3 tables with an added CROSS JOIN
although it takes 6 cross-join sets in the union.
--希望这是一个快速的解决方案,只需更改进入#X的值
--或作为单列结果
--Hopefully this is a quick solution, just change the values going into #X
--or as single column result