【问题标题】:SQL Server Results all possible orderingSQL Server 结果所有可能的排序
【发布时间】:2019-03-25 18:54:43
【问题描述】:

我是这个论坛的新手,正在就以下问题寻求帮助。 我希望从结果集中获得所有可能的排序。 例如

Column1
-------
val1
val2
val3

预期结果

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

【问题讨论】:

  • 请正确粘贴预期结果。
  • 定义“所有可能的排序”

标签: sql sql-server recursion sql-order-by


【解决方案1】:

在我看来,这是一个非常困难的问题。我的解决方案使用两个递归 CTES:

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) 计算所有可能的排序 - 但每个排序只有一行。它遍历数据,构建所有可能的组合,一次一个元素。 cte orderings 实际上是具有完整组合的 cte(在这种情况下长度为 3)。您可能会发现orderings 有您要查找的信息。

第二个递归 cte (splits) 然后扩展拆分以将结果返回到行中。

这是一个有趣的练习,但我不会在一个多于几行的表上运行这样的代码。输出行数为 n * n! (n 阶乘)。这增长得相当快。

我还应该指出,这种类型的逻辑可能更适合在应用程序级别实现,而不是在 SQL 中。但这是一个有趣的 SQL 问题。毕竟解为n * n的问题并不多!原始表中的行。

【讨论】:

  • 感谢您的帮助。但是,给定的解决方案仅在我有 3 行时才有效。示例中给出的 3 行仅用于演示目的。它可以是任意数量的行。我会尝试给出的其他解决方案。再次感谢您的帮助!
  • @Harry 。 . .其实并不是。我也用 4 行和 5 行测试了代码。我不会推荐超过 10 行。 10 行已经是一个包含 36+ 百万行的结果集。
  • 是的,你是对的。它适用于任意数量的行。非常感谢您的帮助。我将此标记为答案。谢谢
【解决方案2】:

考虑到预期的结果,这是一个奇怪的挑战。

但您可以通过自联接来做到这一点。
可用于查找 3 个值的所有组合。

然后对该结果进行反透视以获得预期结果。

示例 sn-p:

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;

【讨论】:

  • 感谢您的回复。我试过了,它适用于 3 个值,但对超过 3 个值无效。再次感谢您的帮助!
  • @Harry True,此方法将找到 3 个不同值的每个组合。表中可以有 3 个以上的值,但自联接的数量决定了它是每组 3 个计算的。哦,好吧,我猜我对要求的理解不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-25
  • 1970-01-01
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多