我有一个如下表,
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
有没有最短的方法来实现这一过程?
答案 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
答案 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
的方法。