按行排序

时间:2019-03-06 05:32:47

标签: sql sql-server

我有一个如下表,

col1    col2    col3
1        2       3
2        1       3
3        2       1
1        4       6
4        6       1
6        4       1

在这里我想对记录行进行排序。

预期的输出。

col1    col2    col3
1        2       3
1        2       3
1        2       3
1        4       6
1        4       6
1        4       6

我使用ASCII值进行比较。

声明@tab表(col1 varchar(10),col2 varchar(10),col3 varchar(20))

insert into @tab
select '4','6','1' union
select '6','4','1' union
select '1','2','3'  union
select '2','1','3'  union
select '3','1','2' union
select '4','2','3'  union
select '1','4','6' union

select '5','5','1' union
select '5','5','1' union

select 'a','2','2' union
select '2','a','2' union
select '2','2','a'



;with CTE as(
    Select Case When ascii(Col1) <=  ascii(Col2) And  ascii(Col1) <=  
                     ascii(Col3) Then  cast(Col1 as varchar)
                When ascii(Col2) <=  ascii(Col1) And  ascii(Col2) <=  
                     ascii(Col3) Then  cast(Col2 as varchar)
                Else cast(Col3 as varchar) END as  col1,
                case when ( ascii(col1) >=  ascii(col2) and  ascii(col2) >=  
                            ascii(col3)) or ( ascii(col3) >=  ascii(col2) and  
                            ascii(col2) >=  ascii(col1)) then cast(Col2 as 
                            varchar) 
               when ( ascii(col1) >=  ascii(col3) and  ascii(col3) >=  
                      ascii(col2)) or ( ascii(col2) >=  ascii(col3) and  
                      ascii(col3) >=  ascii(col1)) then  cast(Col3 as varchar)
               when ( ascii(col3) >=  ascii(col1) and  ascii(col1) >=  ascii(col2)) or ( ascii(col2) >=  ascii(col1) and  ascii(col1) >=  ascii(col3)) then cast(Col1 as varchar) end as col2,
                Case When  ascii(Col1) >=  ascii(Col2) And  ascii(Col1) >=  ascii(Col3) Then  cast(Col1 as varchar)
                When  ascii(Col2) >=  ascii(Col1) And  ascii(Col2) >=  ascii(Col3) Then  cast(Col2 as varchar)
                Else  cast(Col3 as varchar) END as col3
    From   @tab)

    select * from CTE

有没有最短的方法来实现这一过程?

5 个答案:

答案 0 :(得分:2)

这种按行排序的需求通常表明您的表可以从新结构中受益。您真正想完成什么?可以通过将col1,col2和col3规范化以使其看起来更垂直来更好地完成此操作(这是下面“不可透视的” CTE所强制执行的操作,但该表首先应该看起来像这样)。

如果必须执行此操作,请考虑向表中添加行标识符(主要是主键)。

declare @tab table(
    rowId int identity(1,1),
    col1 varchar(10),
    col2 varchar(10),
    col3 varchar(20)
);

insert @tab values
    ('4','6','1'),
    -- etc

然后,您可以避免使用一堆case语句,并且更容易扩展到不止三列,如下所示:

with

    unpivoted as (

        select       rowId, 
                     val,
                     ord = row_number() over(partition by rowId order by val)
        from         @tab
        cross apply  (values (col1), (col2), (col3)) ap (val)

    )

    select    rowId,
              col1 = [1],
              col2 = [2],
              col3 = [3]
    from      unpvioted
    pivot     (max(val) for ord in ([1],[2],[3])) piv

您可以在操作here中看到它。

答案 1 :(得分:2)

使用ROW_NUMBER()的另一种方式,如下所示

SELECT (SELECT x 
        FROM   (SELECT  x, 
                             Row_number() 
                               OVER( 
                                 ORDER BY x) rn 
                FROM   (VALUES(col1), 
                              (col2), 
                              (col3))f(x))t 
        WHERE  rn = 1) c1, 
       (SELECT x 
        FROM   (SELECT  x, 
                             Row_number() 
                               OVER( 
                                 ORDER BY x) rn 
                FROM   (VALUES(col1), 
                              (col2), 
                              (col3))f(x))t 
        WHERE  rn = 2) c2, 
       (SELECT x 
        FROM   (SELECT  x, 
                             Row_number() 
                               OVER( 
                                 ORDER BY x) rn 
                FROM   (VALUES(col1), 
                              (col2), 
                              (col3))f(x))t 
        WHERE  rn = 3) c3 
FROM   @table 

使用嵌套的CTE或如下所示。

  ;WITH cte1 
     AS (SELECT (SELECT Min(f) 
                 FROM   (VALUES (col1), 
                                (col2), 
                                (col3)) AS Fields(f)) m1, 
                * 
         FROM   @table), 
     cte2 
     AS (SELECT (SELECT COALESCE(Min(f), M1) AS M2
                 FROM   (VALUES (col1), 
                                (col2), 
                                (col3)) AS Fields(f) 
                 WHERE  f > m1) m2, 
                * 
         FROM   cte1), 
     cte3 
     AS (SELECT m1, 
                m2, 
                (SELECT COALESCE(Min(f),m2) as m3 
                 FROM   (VALUES (col1), 
                                (col2), 
                                (col3)) AS Fields(f) 
                 WHERE  f > m2) m3 
         FROM   cte2) 
SELECT * 
FROM   cte3 

Online Demo

答案 2 :(得分:0)

如下所示的用例

select case when col1>col2>col3 then col1
        when col2>col3 then col2
        else col3 end as col1, -- this is the condition for first column

您必须为3列编写这种方式

答案 3 :(得分:0)

如果所有列均为整数类型,则下面的查询将起作用,

SELECT c1 = CASE
  WHEN c1 <= c2 AND c1 <= c3 THEN c1
  WHEN c2 <= c1 AND c2 <= c3 THEN c2
  ELSE c3 END,
c2 = CASE 
  WHEN c1 <= c2 AND c1 <= c3 THEN 
    CASE WHEN c2 <= c3 THEN c2 ELSE c3 END
  WHEN c2 <= c1 AND c2 <= c3 THEN
    CASE WHEN c1 <= c3 THEN c1 ELSE c3 END
  ELSE
    CASE WHEN c1 <= c2 THEN c1 ELSE c2 END
  END,
c3 = CASE
  WHEN c1 >= c2 AND c1 >= c3 THEN c1
  WHEN c2 >= c1 AND c2 >= c3 THEN c2
  ELSE c3 END
FROM temp_x;

如果有任何字符,则可以使用ASCII值进行提示。

答案 4 :(得分:0)

最快的方法可能是case表达式,但这并不能一概而论。

我会选择apply作为性能和可伸缩性之间的良好平衡:

select v.*
from t cross apply
     (select max(case when seqnum = 1 then col end) as col1,
             max(case when seqnum = 2 then col end) as col2,
             max(case when seqnum = 3 then col end) as col3             
      from (select v.*,
                   row_number() over (order by col) as seqnum
            from (values (t.col1), (t.col2), (t.col3)) v(col)
           ) v
     ) v;

这也可以轻松处理NULL的值和联系,这极大地简化了case的方法。