SQL Server - 三列的独特组合 - 顺序并不重要

时间:2016-11-16 21:20:02

标签: sql sql-server

我希望在SQL Server中按每个组合计算3列值组合。我怎么得到这个?

实施例



Row    P1   P2   P3
 1     3    10   20
 2     4    15   29
 3     8    10   16
 4     15    4   29
 5     10   20    3

Output Should be:
3  10  20  - 2
4  15  29  - 2
8  10  16  - 1




谢谢,

3 个答案:

答案 0 :(得分:2)

选项1 -

交叉应用,对于xml路径,分组依据。

select      vals,count (*) as cnt
from        t cross apply (select ' ' + cast (p as varchar(10)) from (values (p1),(p2),(p3)) as t(p) order by p for xml path('')) v (vals)
group by    vals
vals        cnt
 3 10 20    2
 4 15 29    2
 8 10 16    1

选项2 -

xquery,分组

select      vals
           ,count (*) as cnt

from       (select      cast ((cast ('' as xml)).query('for $i in (sql:column("p1"),sql:column("p2"),sql:column("p3")) order by $i return $i') as varchar(max)) as vals

            from        t
            ) t

group by    vals
;
vals        cnt
-------     ---
3 10 20     2
4 15 29     2
8 10 16     1

选项3 -

Unpivot,row_number,Pivot。

select      [1],[2],[3],count (*) as cnt
from       (select      row,p,row_number () over (partition by row order by p) as n
            from        t unpivot (p for col in (p1,p2,p3)) upv
            ) t pivot (max(p) for n in ([1],[2],[3])) pv
group by    [1],[2],[3]
1   2   3   cnt
--- --- --- ---
3   10  20  2
4   15  29  2
8   10  16  1

选项4 -

偏移n行,分组依据。

select      [1],[2],[3],count(*) as cnt

from       (select      (select p from (values (p1),(p2),(p3))as t(p) order by p offset 0 rows fetch first 1 row only)  as [1]
                       ,(select p from (values (p1),(p2),(p3))as t(p) order by p offset 1 rows fetch first 1 row only)  as [2]
                       ,(select p from (values (p1),(p2),(p3))as t(p) order by p offset 2 rows fetch first 1 row only)  as [3]

            from        t
            ) t

group by    [1],[2],[3]
1   2   3   cnt
--- --- --- ---
3   10  20  2
4   15  29  2
8   10  16  1

答案 1 :(得分:1)

哦,这是一种痛苦。

select p_1, p_2, p_3, count(*) as cnt
from t cross apply
     (select max(case when seqnum = 1 then p end) as p_1,
             max(case when seqnum = 2 then p end) as p_2,
             max(case when seqnum = 3 then p end) as p_3
      from (select p, row_number() over (order by p) as seqnum
            from (values (p1), (p2), (p3)
                 ) v(p)
           ) rp
     ) rp
group by p_1, p_2, p_3;

这是做什么的? cross apply首先将值展开到单独的行上。然后它枚举值(使用row_number(),按值排序。这将生成一个序列号,用于按顺序旋转值。

最后,在每行按顺序排列值时,我们可以汇总这些值以获得您要求的计数。

答案 2 :(得分:1)

这是另一种方法,在使用case表达式时,3个值中的至少一个被赋予c1,第二个最小的c2和最大的c3。此后,它只是一个分组操作。

select c1,c2,c3,count(*) 
from (
select case when p1<=p2 and p1<=p3 then p1
        when p2<=p1 and p2<=p3 then p2
        when p3<=p1 and p3<=p2 then p3 end c1,
   case when p1 between p2 and p3 or p1 between p3 and p2 then p1
        when p2 between p1 and p3 or p2 between p3 and p1 then p2
        when p3 between p1 and p2 or p3 between p2 and p1 then p3 end c2,
   case when p2<=p1 and p3<=p1 then p1
        when p1<=p2 and p3<=p2 then p2
        when p1<=p3 and p2<=p3 then p3 end c3
from t
) x
group by c1,c2,c3

<强> Sample Demo

这里的假设是p1,p2,p3值都不为空。如果它们可以是null,请在案例表达式中使用coalesce,具体取决于您希望如何处理这些行以进行计数。