我的表中有以下值:
ABC
ABC1
ABC2
ABC3 and so on...
ABC11
ABC12
ABC13 and so on..
ABC20
ABC21
ABC22 and so on..
基本上我所拥有的是任何字符串值(不总是ABC,任何字符串值),可以跟随数字,也可以只是没有数字的字符串。
当我通过我的列asc从表顺序中选择*时,我得到以下结果:
ABC
ABC1
ABC11
ABC12
ABC13
ABC2
ABC20
ABC21
ABC22
ABC3
ABC31
ABC32
我需要用数字排序:
ABC
ABC1
ABC2
ABC3
ABC11
ABC12
ABC13
ABC20
ABC21
ABC22
ABC31
ABC32
如何实现这一目标?
答案 0 :(得分:12)
您可以使用PATINDEX()函数执行此操作,如下所示:
select * from Test
order by CAST(SUBSTRING(Name + '0', PATINDEX('%[0-9]%', Name + '0'), LEN(Name + '0')) AS INT)
<强> SQL Fiddle Demo 强>
如果您在字符串中间有数字,那么您需要创建小的用户定义函数以从字符串中获取数字并根据该数字对数据进行排序,如下所示:
CREATE FUNCTION dbo.fnGetNumberFromString (@strInput VARCHAR(255))
RETURNS VARCHAR(255)
AS
BEGIN
DECLARE @intNumber int
SET @intNumber = PATINDEX('%[^0-9]%', @strInput)
WHILE @intNumber > 0
BEGIN
SET @strInput = STUFF(@strInput, @intNumber, 1, '')
SET @intNumber = PATINDEX('%[^0-9]%', @strInput)
END
RETURN ISNULL(@strInput,0)
END
GO
您可以按以下方式对数据进行排序:
select Name from Test order by dbo.fnGetNumberFromString(Name), Name
答案 1 :(得分:5)
您可以删除前三个字符,然后将其余字符转换为int
SELECT Value,
Num=CAST(RIGHT(Value, LEN(Value) - 3) AS int)
FROM dbo.TableName
ORDER BY Num
答案 2 :(得分:2)
您可以调整this answer中的函数 RemoveNonAlphaCharacters 来过滤掉除数字之外的所有内容,然后使用该函数使用ORDER BY
。
答案 3 :(得分:2)
按顺序声明,在值包含任何数字时,前缀足够零以使所有字母数字值相同
x² or xⁿ
答案 4 :(得分:1)
(基于从@shenhengbin和@EchO到this question的答案)
以下是我所说的“干净的hack”。假设您正在RUNAS
列上订购:
Col1
这是一个hack,尽管我个人对此感到自豪。
答案 5 :(得分:0)
仅使用标准 SQL 此查询演示了如何 ODER BY 找到包含在字符串开头或结尾的数字。该查询还显示了如何查看字符串剩余的“内部”部分以查看其中是否包含任何数字。如果需要进一步处理,了解字符串中是否包含数字可能会很有用。
WITH stringNumberData AS
( /* Build up Fake data with Numbers at the Beginning, End and Middle of the string */
SELECT 1 AS uniqueKey, 'ABC' AS NumberFromString UNION ALL
SELECT 2 AS uniqueKey, 'ABC1' AS NumberFromString UNION ALL
SELECT 3 AS uniqueKey, 'ABC2' AS NumberFromString UNION ALL
SELECT 4 AS uniqueKey, 'ABC3' AS NumberFromString UNION ALL
SELECT 5 AS uniqueKey, 'ABC10' AS NumberFromString UNION ALL
SELECT 6 AS uniqueKey, 'ABC11' AS NumberFromString UNION ALL
SELECT 7 AS uniqueKey, 'ABC12' AS NumberFromString UNION ALL
SELECT 8 AS uniqueKey, 'ABC20' AS NumberFromString UNION ALL
SELECT 9 AS uniqueKey, 'ABC21' AS NumberFromString UNION ALL
SELECT 10 AS uniqueKey, 'ABC22' AS NumberFromString UNION ALL
SELECT 11 AS uniqueKey, 'ABC30' AS NumberFromString UNION ALL
SELECT 12 AS uniqueKey, 'ABC31' AS NumberFromString UNION ALL
SELECT 13 AS uniqueKey, 'ABC32' AS NumberFromString UNION ALL
SELECT 14 AS uniqueKey, '1ABC' AS NumberFromString UNION ALL
SELECT 15 AS uniqueKey, '2ABC' AS NumberFromString UNION ALL
SELECT 16 AS uniqueKey, '3ABC' AS NumberFromString UNION ALL
SELECT 17 AS uniqueKey, '10ABC' AS NumberFromString UNION ALL
SELECT 18 AS uniqueKey, '11BC' AS NumberFromString UNION ALL
SELECT 19 AS uniqueKey, '12ABC' AS NumberFromString UNION ALL
SELECT 20 AS uniqueKey, '10ABC18' AS NumberFromString UNION ALL
SELECT 21 AS uniqueKey, '11BC52' AS NumberFromString UNION ALL
SELECT 22 AS uniqueKey, '12ABC42' AS NumberFromString UNION ALL
SELECT 23 AS uniqueKey, 'A3BC18' AS NumberFromString UNION ALL
SELECT 24 AS uniqueKey, 'B3C52' AS NumberFromString UNION ALL
SELECT 25 AS uniqueKey, '12AB3C' AS NumberFromString UNION ALL
SELECT 26 AS uniqueKey, 'A3BC' AS NumberFromString UNION ALL
SELECT 27 AS uniqueKey, 'AB2C' AS NumberFromString UNION ALL
SELECT 28 AS uniqueKey, 'ABC85D' AS NumberFromString
)
SELECT d.uniqueKey, d.NumberFromString
/* Extract numerical values contained on the LEFT of the String by finding the index of the first non number */
, LEFT(d.NumberFromString, PATINDEX('%[^0-9]%', d.NumberFromString) -1) AS 'Left Numbers Extraction'
/* Extract numerical data contained on the RIGHT of the String */
, RIGHT(d.NumberFromString, PATINDEX('%[^0-9]%', REVERSE(d.NumberFromString)) - 1 ) AS 'Right Numbers Extraction'
/* The below checks inside the Inner string to determine if numbers exists within it. Could be used for further processing if further extraction is necessary */
, PATINDEX('%[0-9]%',
SUBSTRING(d.NumberFromString /*, Start Pos, Length to Extract) */
, PATINDEX('%[^0-9]%', d.NumberFromString) /* Start Pos is first left non number */
/* The below obtains the length of the Inner String so it can be extracted */
, LEN(d.NumberFromString) - ((PATINDEX('%[^0-9]%', d.NumberFromString) -1 )) - (PATINDEX('%[^0-9]%', REVERSE(d.NumberFromString)) -1) /* (String Length) - (LEFT Numbers) - (RIGHT Numbers) */
)) AS innerNumExists
/* The two lines below tell us if there exists a number at the Beginning and/or End of the string */
, PATINDEX('%[0-9]%', LEFT(d.NumberFromString, 1)) AS leftNumExists
, PATINDEX('%[0-9]%', RIGHT(d.NumberFromString, 1)) AS rightNumExists
/* Locates and returns the index of the very first number located in the string from Left to Right */
, PATINDEX('%[^0-9]%', d.NumberFromString) AS firstLeftNonNum_index
/* Locates and returns the index of the very first number located in the string from Right to Left */
, LEN(d.NumberFromString) - (PATINDEX('%[^0-9]%', REVERSE(d.NumberFromString)) -1 ) AS firstRightNonNum_index
/* Get the length of the numbers existing from Right to Left up to the first non numeric character */
, PATINDEX('%[^0-9]%', REVERSE(d.NumberFromString)) -1 AS rightStringLen
FROM stringNumberData d
ORDER BY
/* Ordering first by numbers found on the LEFT of the string */
CAST(LEFT(d.NumberFromString, PATINDEX('%[^0-9]%', d.NumberFromString) -1) AS INT )
/* Ordering second by numbers found on the RIGHT of the string */
, CAST(RIGHT(d.NumberFromString, PATINDEX('%[^0-9]%', REVERSE(d.NumberFromString)) - 1 ) AS INT )
;
答案 6 :(得分:0)
这里有一个简单易懂的示例,适合使用 SQL Server 17+ 的用户。
DECLARE @Data table ( val varchar(10) );
INSERT INTO @Data VALUES
( 'ABC' ),( 'ABC1' ),( 'ABC11' ),( 'ABC12' ),( 'ABC13' ),( 'ABC2' ), ( 'B1C' ),
( 'ABC20' ),( 'ABC21' ),( 'ABC22' ),( 'ABC3' ),( 'ABC31' ),( 'ABC32' );
SELECT val FROM @Data AS d
CROSS APPLY (
SELECT CAST ( TRANSLATE ( d.val, 'abcdefghijklmnopqrstuvwxyz', ' ' ) AS int ) AS Num
) AS x
ORDER BY
LEFT ( val, 1 ), Num;
退货
+-------+
| val |
+-------+
| ABC |
| ABC1 |
| ABC2 |
| ABC3 |
| ABC11 |
| ABC12 |
| ABC13 |
| ABC20 |
| ABC21 |
| ABC22 |
| ABC31 |
| ABC32 |
| B1C |
+-------+
SQL Server 的 TRANSLATE 需要三个参数:inputString, characters, translations
。
您的案例中的 inputString
是您的列名。
characters
是您要替换的值,在本例中是字母表。
translations
是要替换的值。此字符串的长度必须与 characters
的长度相等——因此是 26 个空格长的空字符串。
最后,使用 CAST
会忽略空格并允许将剩余的值作为整数进行排序。
您可以在此处阅读有关 TRANSLATE 的信息:
https://docs.microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql?view=sql-server-ver15