【问题标题】:Sorting VARCHAR column which contains integers对包含整数的 VARCHAR 列进行排序
【发布时间】:2021-10-23 05:35:41
【问题描述】:

我有这张桌子:

IF OBJECT_ID('tempdb..#Test') IS NOT NULL 
    DROP TABLE #Test;

CREATE TABLE #Test (Col VARCHAR(100));

INSERT INTO #Test 
VALUES ('1'), ('2'), ('10'), ('A'), ('B'), ('C1'), ('1D'), ('10HH')

SELECT * FROM #Test

我想先按数值排序,然后按字母排序。

我想要的结果是:

1
1D
2
10
10HH
A
B
C1

假设条目的结构是其中之一(当然没有破折号)

number
number-string
string-number
string

如果有类似string-number-string的条目,假设它是string-number

【问题讨论】:

  • 'C1' 怎么样,它是如何工作的? 'C2'大于'c10'吗?
  • 是的,C2 大于 C10,但那部分并不重要。无论哪种方式都有效。最重要的是开始整数
  • ...和C4CC41C
  • 如果你有A2BA10B20,它们会如何排序?
  • @AaronBertrand,那部分无关紧要。理想情况下,C4C 在 C41C 之前。不过没关系

标签: sql sql-server tsql


【解决方案1】:

漂亮,但它有效。

SELECT T.Col
FROM #Test T
     CROSS APPLY (VALUES(PATINDEX('%[^0-9]%',T.Col)))PI(I)
     CROSS APPLY (VALUES(TRY_CONVERT(int,NULLIF(ISNULL(LEFT(T.Col,NULLIF(PI.I,0)-1),LEN(T.Col)),''))))TC(L)
ORDER BY CASE WHEN TC.L IS NULL THEN 1 ELSE 0 END,
         TC.L,
         T.Col;

老实说,我建议如果您想像数值一样对数据进行排序,您实际上存储数值列中的数值;显然上面应该是数字前缀值,然后是字符串后缀。然后,如果您想要拥有您拥有的值,请使用 (PERSISTED) 计算列。像这样:

CREATE TABLE #Test (Prefix int NULL,
                    Suffix varchar(100) NULL,
                    Col AS CONCAT(Prefix, Suffix) PERSISTED);

INSERT INTO #Test (Prefix, Suffix)
VALUES (1,NULL), (2,NULL), (10,NULL), (NULL,'A'), (NULL,'B'), (NULL,'C1'), (1,'D'), (10,'HH');

SELECT Col
FROM #Test
ORDER BY CASE WHEN Prefix IS NULL THEN 1 ELSE 0 END,
         Prefix,
         Suffix;

【讨论】:

  • 抱歉,走神了!
  • 我很困惑,@AaronBertrand,因为什么?
  • (1) 我开始做小提琴 (2) 分心了 (3) 发布了我的答案 (4) 注意到你同时发布了一个答案 (5) 在我给你之前又分心了投票你应得的。 :-) 在我的职业生涯的剩余时间里,我可能会倾向于 CTE 而不是 CROSS APPLY 以避免重复。
  • 别担心,在编写上述内容时,我至少两次被 F1 分心,@AaronBertrand。 :)
  • @AaronBertrand APPLY 绝对是蜜蜂的膝盖,没有它我绝对会在 SQL 中瘫痪。请参阅stackoverflow.com/a/65818648/14868997 这比重复的 CTE 或嵌套派生表要容易得多
【解决方案2】:

这种糟糕且不直观的解决方案,如果您将这两条数据分开存储,那将是不必要的,它是由 bad idea designs™ 带来的:

;WITH cte AS 
(
  SELECT Col, rest = SUBSTRING(Col, pos, 100),
    possible_int = TRY_CONVERT(bigint, CASE WHEN pos <> 1 THEN 
    LEFT(Col, COALESCE(NULLIF(pos,0),100)-1) END)
  FROM (SELECT Col, pos = PATINDEX('%[^0-9]%', Col) FROM #Test) AS src
)
SELECT Col FROM cte
ORDER BY CASE 
  WHEN possible_int IS NULL THEN 2 ELSE 1 END, 
  possible_int, 
  rest;

结果:

Col
1
1D
2
10
10HH
A
B
C1

【讨论】:

    猜你喜欢
    • 2018-09-05
    • 2013-10-16
    • 1970-01-01
    • 2010-09-12
    • 2011-05-04
    • 2010-09-15
    • 2014-06-21
    • 1970-01-01
    • 2019-09-18
    相关资源
    最近更新 更多