我正在选择客户订单,我按customer_name订购。
客户名称很有趣,他们就是这样的
当我写下面的查询时
select customer_name from orders order by customer_name
这就是我得到的
请注意 - 一些客户#2追求 - 一些客户#11
I found this post which says to do the following:
ORDER BY
CASE WHEN customer_name not like '%[0-9]%' THEN customer_name ELSE
STUFF(customer_name, PATINDEX('%[0-9]%',customer_name), 0, replicate('0',
PATINDEX('%[0-9]%',customer_name) - len(customer_name) + PATINDEX('%[0-9]%',reverse(customer_name)) + 6))
END
最后通过数字订购是否有更好的方式?
答案 0 :(得分:2)
如果所有数字都以'#'
开头,那么您可以执行以下操作:
order by (case when customer_name not like '%#%' then customer_name
else left(customer_name, charindex('#', customer_name))
end),
len(customer_name),
customer_name
你可以尝试提取字符串末尾的数字(如果存在),但是如果你的问题中有格式,这应该可行。
答案 1 :(得分:2)
这是两部分答案:)
要做的第一件事是找到一种方法来规范化具有"#"的company_name值。由于这是一个字符串字段,它将根据其位置对数字进行排序,而不是基于它们的值。因此,不要将此值拆分为多个字段以放入ORDER BY
,而是让客户编号的字符串表示 可排序。意思是,而" 2"自然而然地出现在" 10"在他们是字符串方面," 02"正如预期的那样来之前的" 10"看看以下内容:
SET NOCOUNT ON;
SET ANSI_NULLS ON;
-- DROP TABLE #Orders
CREATE TABLE #Orders
(
OrderID INT IDENTITY(1, 1) NOT NULL,
CustomerName NVARCHAR(50) NOT NULL
);
INSERT INTO #Orders (CustomerName) VALUES ('A Customer');
INSERT INTO #Orders (CustomerName) VALUES ('A Customer #1');
INSERT INTO #Orders (CustomerName) VALUES ('A Customer #2');
INSERT INTO #Orders (CustomerName) VALUES ('Some customer #1');
INSERT INTO #Orders (CustomerName) VALUES ('Some customer #2');
INSERT INTO #Orders (CustomerName) VALUES ('Some customer #10');
INSERT INTO #Orders (CustomerName) VALUES ('Some customer #11');
SELECT *,
CASE WHEN CustomerName LIKE N'%#%' THEN
STUFF(
[CustomerName],
(CHARINDEX(N'#', [CustomerName]) + 1), -- start just after the "#"
0, -- don't overwrite anything
REPLICATE(N'0',
(6 - (LEN([CustomerName]) - CHARINDEX(N'#', [CustomerName])))
) -- ensure 6 digits
)
ELSE [CustomerName]
END AS [SortName-test]
FROM #Orders
ORDER BY [SortName-test];
结果如您所愿。
当然,你可以总是把这个表达式放在ORDER BY
中,如下所示:
SELECT *
FROM #Orders
ORDER BY
CASE WHEN CustomerName LIKE N'%#%' THEN
STUFF(
[CustomerName],
(CHARINDEX(N'#', [CustomerName]) + 1), -- start just after the "#"
0, -- don't overwrite anything
REPLICATE(N'0',
(6 - (LEN([CustomerName]) - CHARINDEX(N'#', [CustomerName])))
) -- ensure 6 digits
)
ELSE [CustomerName]
END;
但是,根据表的大小以及此字段在ORDER BY
(或甚至是GROUP BY
或任何其他需要排序的操作)中使用的频率,执行on-the -fly操作可能非常昂贵,并且无法编入索引。
在这种情况下,可以将其添加为PERSISTED COMPUTED COLUMN
。因为它是"计算"它会随着基础[company_name]
字段中值的任何更改而适当更改。由于它是"持久的",a)该值将存在,甚至可以被查询优化器使用,并且b)它可以被索引以获得更好的效果。
跑步:
ALTER TABLE #Orders ADD [SortName] AS (CASE WHEN CustomerName LIKE N'%#%' THEN
STUFF(
[CustomerName],
(CHARINDEX(N'#', [CustomerName]) + 1), -- start just after the "#"
0, -- don't overwrite anything
REPLICATE(N'0',
(6 - (LEN([CustomerName]) - CHARINDEX(N'#', [CustomerName]))))
) -- ensure 6 digits
ELSE [CustomerName]
END) PERSISTED;
这让你有了一个非常复杂的查询:
SELECT *
FROM #Orders
ORDER BY [SortName];
答案 2 :(得分:0)
您可以将客户名称分成两部分:前面的字符串,尾随的数字和按字符串排序的数字。
见:
SELECT *, LEFT(customer_name, LEN(customer_name) - PATINDEX('%[0-9][^0-9]%', REVERSE(customer_name) )),
RIGHT(customer_name, PATINDEX('%[0-9][^0-9]%', REVERSE(customer_name) ))
FROM @Orders
ORDER BY LEFT(customer_name, LEN(customer_name) - PATINDEX('%[0-9][^0-9]%', REVERSE(customer_name) )),
CAST(RIGHT(customer_name, PATINDEX('%[0-9][^0-9]%', REVERSE(customer_name) )) AS INT)
即使没有'#'在customer_name内,即使customer_name中有另一个数字,例如使用Customer 12
,Jonn 2 Smith #12
等
答案 3 :(得分:0)
试试这个。简单的方法是
ORDER BY CASE
WHEN customer_name NOT LIKE '%#%' THEN '0'
WHEN customer_name LIKE '%#%' THEN LEFT(customer_name, Len(customer_name) - Charindex('#', customer_name))
END,
RIGHT(customer_name, Len(customer_name) - Charindex('#', customer_name))