SQL 非特定格式的字母数字排序
SQL alphanumerical sorting with non specific format
我必须对不共享相同格式的字符串进行排序,但我很难找到解决这个问题的方法。为此在 Whosebug 上尝试了几个选项,但它对我不起作用,因为它们适用于特定格式的数据。
这是我必须排序的数据示例。
12-ABC
1-ABC
ABC-10
ABC-11
ABC-100
2-ABCD
ABC-100A
我用 ORDER BY
得到了这样的结果
1-ABC
12-ABC
2-ABCD
ABC-10
ABC-100
ABC-100A
ABC-11
但是我想要这个
1-ABC
2-ABCD
12-ABC
ABC-10
ABC-11
ABC-100
ABC-100A
你会怎么做?
您可以将字符串拆分为数字和文本(在“-”上),然后按 num 列排序。类似于:
select iif((charindex('-', str) > 0), (cast(substring(str, 1, (charindex('-', str)-1)) as integer)), 9999) as num, str
from (
select '1-ABC' as str union all
select '2-ABC' as str union all
select '12-ABC' as str union all
select 'ABC' as str
) tbl
order by num, str
这样您将首先按数值排序,然后按字符串排序。在这里,我只是在 none 数字值中添加了一个非常高的数字,因此它将排在最后。
这是一个复杂的问题。解析字符串是 SQL 不是一般设计的,特别是 SQL 服务器。
您正在尝试从字符串的两个部分中提取一个数字并按该数字排序。啊!这确实表明您正在将多种类型的信息存储在一个字符串中——在单独的列中可能会更好地表示这些信息。
也就是说,你可以做你想做的事。这是一种适用于您在问题中提供的数据的方法:
select t.str
from (values ('1-ABC'),
('12-ABC'),
('2-ABCD'),
('ABC-10'),
('ABC-100'),
('ABC-100A'),
('ABC-11')
) t(str) cross apply
(values (left(str, charindex('-', str + '-') - 1), stuff(str, 1, charindex('-', str), ''))
) v(part1, part2)
order by coalesce(try_convert(int, v.part1), 999999999),
part1,
try_convert(int, left(v.part2, patindex('%[^0-9]%', v.part2 + 'x') - 1)),
part2;
Here 是一个 db<>fiddle.
感谢大家提供的所有信息。我设法让这个东西在这个特殊情况下几乎完美地工作。
select distinct PCE_NAM,
--FIRST SECTION OF THE STRING
--REPLICATE to fill 0s before numerics
(CASE
WHEN CHARINDEX('-', PCE_NAM) = 0 then PCE_NAM
WHEN CHARINDEX('-', PCE_NAM) > 0 and
ISNUMERIC(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)) = 1 and
LEN(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)) <= 8
then REPLICATE('0', 8-LEN(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1))) + LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)
ELSE LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)
END) as FirstPart,
--SECOND SECTION OF THE STRING
(CASE
WHEN CHARINDEX('-', PCE_NAM) = 0 then ''
WHEN CHARINDEX('-', PCE_NAM) > 0 and
ISNUMERIC(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))) = 1 and
LEN(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))) <= 8
then REPLICATE('0', 8-LEN(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)))) + SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))
ELSE SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))
END) as SecondPart,
--GET THE NUMERICS ONLY FROM THE SECOND SECTION SO CAN SORT PROPERLY
(CASE
WHEN LEN(LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))) <= 8
then REPLICATE('0', 8-LEN(
LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)))))) +
LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))
ELSE LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))
END) as SecondPartF
from PARTS
order by FirstPart, SecondPartF, SecondPart
我必须对不共享相同格式的字符串进行排序,但我很难找到解决这个问题的方法。为此在 Whosebug 上尝试了几个选项,但它对我不起作用,因为它们适用于特定格式的数据。
这是我必须排序的数据示例。
12-ABC
1-ABC
ABC-10
ABC-11
ABC-100
2-ABCD
ABC-100A
我用 ORDER BY
得到了这样的结果1-ABC
12-ABC
2-ABCD
ABC-10
ABC-100
ABC-100A
ABC-11
但是我想要这个
1-ABC
2-ABCD
12-ABC
ABC-10
ABC-11
ABC-100
ABC-100A
你会怎么做?
您可以将字符串拆分为数字和文本(在“-”上),然后按 num 列排序。类似于:
select iif((charindex('-', str) > 0), (cast(substring(str, 1, (charindex('-', str)-1)) as integer)), 9999) as num, str
from (
select '1-ABC' as str union all
select '2-ABC' as str union all
select '12-ABC' as str union all
select 'ABC' as str
) tbl
order by num, str
这样您将首先按数值排序,然后按字符串排序。在这里,我只是在 none 数字值中添加了一个非常高的数字,因此它将排在最后。
这是一个复杂的问题。解析字符串是 SQL 不是一般设计的,特别是 SQL 服务器。
您正在尝试从字符串的两个部分中提取一个数字并按该数字排序。啊!这确实表明您正在将多种类型的信息存储在一个字符串中——在单独的列中可能会更好地表示这些信息。
也就是说,你可以做你想做的事。这是一种适用于您在问题中提供的数据的方法:
select t.str
from (values ('1-ABC'),
('12-ABC'),
('2-ABCD'),
('ABC-10'),
('ABC-100'),
('ABC-100A'),
('ABC-11')
) t(str) cross apply
(values (left(str, charindex('-', str + '-') - 1), stuff(str, 1, charindex('-', str), ''))
) v(part1, part2)
order by coalesce(try_convert(int, v.part1), 999999999),
part1,
try_convert(int, left(v.part2, patindex('%[^0-9]%', v.part2 + 'x') - 1)),
part2;
Here 是一个 db<>fiddle.
感谢大家提供的所有信息。我设法让这个东西在这个特殊情况下几乎完美地工作。
select distinct PCE_NAM,
--FIRST SECTION OF THE STRING
--REPLICATE to fill 0s before numerics
(CASE
WHEN CHARINDEX('-', PCE_NAM) = 0 then PCE_NAM
WHEN CHARINDEX('-', PCE_NAM) > 0 and
ISNUMERIC(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)) = 1 and
LEN(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)) <= 8
then REPLICATE('0', 8-LEN(LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1))) + LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)
ELSE LEFT(PCE_NAM, CHARINDEX('-', PCE_NAM) -1)
END) as FirstPart,
--SECOND SECTION OF THE STRING
(CASE
WHEN CHARINDEX('-', PCE_NAM) = 0 then ''
WHEN CHARINDEX('-', PCE_NAM) > 0 and
ISNUMERIC(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))) = 1 and
LEN(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))) <= 8
then REPLICATE('0', 8-LEN(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)))) + SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))
ELSE SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))
END) as SecondPart,
--GET THE NUMERICS ONLY FROM THE SECOND SECTION SO CAN SORT PROPERLY
(CASE
WHEN LEN(LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))) <= 8
then REPLICATE('0', 8-LEN(
LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)))))) +
LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))
ELSE LEFT(SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM)), PATINDEX('%[0-9][^0-9]%', SUBSTRING(PCE_NAM, CHARINDEX('-', PCE_NAM)+1, LEN(PCE_NAM))))
END) as SecondPartF
from PARTS
order by FirstPart, SecondPartF, SecondPart