【问题标题】:SQL Sort Numeric Strings After SplitSQL 对拆分后的数字字符串进行排序
【发布时间】:2017-08-18 01:59:11
【问题描述】:

我目前在表格列中有字符值,其格式为“IS-”,然后是 1 到 5 个数字,一个可能的句点有 2 个数字或句点后面的一个字母。

例如,IS-1、IS-12、IS-123、IS-123.11、IS-123.a。

我需要拆分字符串,以便仅抓取数字部分,对字符串进行 ASC 排序,然后将字符串按原样重新组合在一起。

解释。我有以下一组值,IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a. 如您所见,因为 IS-1 在 IS-8 之前,所以它们按数字顺序排序。

知道从哪里开始吗?我正在考虑使用 CASE,但我不确定如何进行。

谢谢。

【问题讨论】:

标签: sql sql-server-2008


【解决方案1】:

在您的ORDER BY 中执行字符串函数以仅删除数字。像这样的东西应该可以工作:

SELECT col
FROM table
ORDER BY CAST(CASE WHEN ISNUMERIC(SUBSTRING(col,4,20)) = 1
              THEN SUBSTRING(col,4,20)
              ELSE LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1)
         END AS NUMERIC)

这将首先删除IS- 并检查字符串的其余部分是否为数字。如果是,则保留十进制数字,否则将删除. 和以下字母字符。

这是假设您在数字小数位的情况下的预期排序为:

IS-123.A
IS-123.1
IS-123.2

如果您不关心小数点/句点后的内容,那么只需:

ORDER BY CAST(LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1) AS NUMERIC)

【讨论】:

  • Das ist fantastisch:)
  • 哇!谢谢亚伦。完美。
【解决方案2】:

如果我理解正确,这可能会对你有所帮助:

DECLARE @mockup TABLE(ID INT IDENTITY,YourExample VARCHAR(100));
INSERT INTO @mockup VALUES
 ('IS-1, IS-12, IS-123, IS-123.11, IS-123.a.')
,('IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a');

WITH Splitted AS
(
    SELECT *
          ,CAST('<x>' + REPLACE(m.YourExample,',','</x><x>') + '</x>' AS XML) AS SplitAtComma
    FROM @mockup AS m
)
,NumberExtracted AS
(
    SELECT s.ID
          ,part.value('text()[1]','nvarchar(max)') AS OnePart
          ,CAST('<y>' + REPLACE(REPLACE(part.value('text()[1]','nvarchar(max)'),'.','-'),'-','</y><y>') + '</y>' AS XML).value('/y[2]/text()[1]','int') AS TheNumber 
    FROM Splitted AS s
    CROSS APPLY s.SplitAtComma.nodes('/x') AS A(part)
)
SELECT *
FROM NumberExtracted
ORDER BY ID,TheNumber;

第一个 CTE 通过 XML 使用字符串拆分来获取原始字符串中的所有值(顺便说一句:永远不要存储逗号分隔的值!)。 第二个 CTE 将使用相同的方法来提取数字,类型安全为 INT。 您最终可以在ORDER BY 中使用它。

结果:

+----+-----------+-----------+
| ID | OnePart   | TheNumber |
+----+-----------+-----------+
| 1  | IS-1      | 1         |
+----+-----------+-----------+
| 1  | IS-12     | 12        |
+----+-----------+-----------+
| 1  | IS-123    | 123       |
+----+-----------+-----------+
| 1  | IS-123.11 | 123       |
+----+-----------+-----------+
| 1  | IS-123.a. | 123       |
+----+-----------+-----------+
| 2  | IS-870.a  | 870       |
+----+-----------+-----------+
| 2  | IS-871.a  | 871       |
+----+-----------+-----------+
| 2  | IS-872.a  | 872       |
+----+-----------+-----------+
| 2  | IS-1170   | 1170      |
+----+-----------+-----------+
| 2  | IS-1171   | 1171      |
+----+-----------+-----------+
| 2  | IS-1172   | 1172      |
+----+-----------+-----------+
| 2  | IS-1173   | 1173      |
+----+-----------+-----------+
| 2  | IS-1174   | 1174      |
+----+-----------+-----------+

【讨论】:

  • 提示:您必须使用LTRIM 和/或RTRIM 来避免前导或尾随空格...
【解决方案3】:
IF OBJECT_ID(N'tempdb..##table1', N'U') IS NOT NULL   
DROP TABLE ##table1;  
create table ##table1(col1 varchar(20))

declare @query as nvarchar(max)
declare @var1 as varchar(max)='IS-1, IS-12, IS-123, IS-123.11, IS-123.a.,IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a.'
set @var1=replace(@var1,',','''),(''')
set @var1='('''+@var1+''')'
set @var1=replace(@var1,' ','')
set @query='insert into ##table1 values'+@var1
EXEC sp_executesql @query
IF OBJECT_ID(N'tempdb..##table2', N'U') IS NOT NULL   
DROP TABLE ##table2;  
select * into ##table2  from ##table1 order by cast(replace(replace(replace(col1,'IS-',''),'.a.',''),'.a','') as float)

declare @results varchar(max)
select @results = coalesce(@results + ', ', '') +  convert(varchar(12),col1) from ##table2
select @results

DROP TABLE ##table1 
DROP TABLE ##table2 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 1970-01-01
    • 2017-07-17
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多