SQL Server将生成所有可能的排序结果
我是这个论坛的新成员,正在以下问题上寻求帮助。 我希望从结果集中获得所有可能的排序。 e、 g 预期结果SQL Server将生成所有可能的排序结果,sql,sql-server,recursion,sql-order-by,Sql,Sql Server,Recursion,Sql Order By,我是这个论坛的新成员,正在以下问题上寻求帮助。 我希望从结果集中获得所有可能的排序。 e、 g 预期结果 RowNumCoumn Column1 ----------- ------- 1 Val1 2 Val2 3 Val3 4 Val1 5 Val3 6 Val2 7 Val2 8
RowNumCoumn Column1
----------- -------
1 Val1
2 Val2
3 Val3
4 Val1
5 Val3
6 Val2
7 Val2
8 Val1
9 Val3
10 Val2
11 Val3
12 Val1
13 Val3
14 Val1
15 Val2
16 Val3
17 Val2
18 Val1
在我看来,这是一个非常困难的问题。我的解决方案使用两个递归CTE:
with t as (select * from (values ('a'), ('b'), ('c')) v(col)),
tn as (
select row_number() over (order by col) as n, col
from t
),
cte as (
select ',' + cast(n as varchar(max)) + ',' as ordering,
cast(col as varchar(max)) + ',' as columns,
1 as lev
from tn
union all
select cte.ordering+ cast(tn.n as varchar(max)) + ',' ,
cast(cte.columns + tn.col as varchar(max)) + ',',
lev + 1
from cte join
tn
on cte.ordering not like '%,' + cast(tn.n as varchar(max)) + ',%'
),
orderings as (
select top (1) with ties cte.*
from cte
order by lev desc
),
splits as (
select ordering, columns,
left(columns, charindex(',', columns) - 1) as val,
stuff(columns, 1, charindex(',', columns) , '') as rest,
1 as lev
from orderings
union all
select ordering, columns,
left(rest, charindex(',', rest) - 1) as val,
stuff(rest, 1, charindex(',', rest), '') as rest,
lev + 1
from splits
where rest like '%,%'
)
select *
from splits;
order by ordering, lev;
(当然,逗号是值的任意分隔符。如果值可能已经有逗号,您可以将其更改为任何您想要的内容)
第一个递归cte(cte
)计算所有可能的排序——但每一个都只有一行。它遍历数据,构造所有可能的组合,一次一个元素。cteorderings
实际上是具有完整组合(在本例中长度为3)的cte。您可能会发现,orderings
中包含您要查找的信息
第二个递归cte(拆分
)然后展开拆分以将结果返回到行中
这是一个有趣的练习,但我不会在一个包含多行的表上运行这样的代码。输出行数为n*n!(n阶乘)。这个增长相当快
我还应该注意,这种逻辑可能更适合在应用程序级别实现,而不是在SQL中实现。但这是一个有趣的SQL问题。毕竟,解决方案是n*n的问题并不多!原始表中的行。考虑到预期的结果,这有点奇怪 但您可以通过自联接来完成此操作。
可用于查找3个值的所有组合 然后取消激活该结果以获得预期结果 示例代码片段:
请正确粘贴预期结果。定义“所有可能的订购”,谢谢您的帮助。但是,给定的解决方案仅在我有3行时有效。示例中给出的3行仅用于演示。它可以是任意数量的行。我将尝试给出的其他解决方案。再次感谢你的帮助@骚扰其实不是。我还用4行和5行测试了代码。我建议不要超过10行。10行已经是3600多万行的结果集。是的,你是对的。它适用于任意数量的行。非常感谢你的帮助。我将此标记为答案。谢谢你的回复。我试过了,它对3种价值观都很有效,但只对3种价值观有效。再次感谢你的帮助@Harry True,此方法将查找3个不同值的每个组合。表中可以有3个以上的值,但自联接的数量决定了它是按每组3计算的。哦,好吧,我想我对这个要求有不同的理解。
with t as (select * from (values ('a'), ('b'), ('c')) v(col)),
tn as (
select row_number() over (order by col) as n, col
from t
),
cte as (
select ',' + cast(n as varchar(max)) + ',' as ordering,
cast(col as varchar(max)) + ',' as columns,
1 as lev
from tn
union all
select cte.ordering+ cast(tn.n as varchar(max)) + ',' ,
cast(cte.columns + tn.col as varchar(max)) + ',',
lev + 1
from cte join
tn
on cte.ordering not like '%,' + cast(tn.n as varchar(max)) + ',%'
),
orderings as (
select top (1) with ties cte.*
from cte
order by lev desc
),
splits as (
select ordering, columns,
left(columns, charindex(',', columns) - 1) as val,
stuff(columns, 1, charindex(',', columns) , '') as rest,
1 as lev
from orderings
union all
select ordering, columns,
left(rest, charindex(',', rest) - 1) as val,
stuff(rest, 1, charindex(',', rest), '') as rest,
lev + 1
from splits
where rest like '%,%'
)
select *
from splits;
order by ordering, lev;
declare @Table table (Column1 varchar(30));
insert into @Table (Column1) values
('val1'),
('val2'),
('val3');
select
row_number() over (order by rn, Col) as RowNumColumn,
Val as Column1
from
(
select
t1.Column1 as Col1,
t2.Column1 as Col2,
t3.Column1 as Col3,
row_number() over (order by t1.Column1, t2.Column1, t3.Column1) as rn
from @Table as t1
left join @Table as t2 on t2.Column1 != t1.Column1
left join @Table as t3 on t3.Column1 not in (t1.Column1, t2.Column1)
) src
UNPIVOT (
Val
FOR Col IN ([Col1], [Col2], [Col3])
) as unpvt
order by RowNumColumn;