Pav*_*vla 2 sql-server-2008 sql-server order-by case
我有一个包含一些项目代码的表格。这些代码是
e.g.: B001, B002, Z15001, Z14001, P003,...
Run Code Online (Sandbox Code Playgroud)
我需要这个结果表:
Z15001
Z15002
...
B001
B002
...
C001
C002
...
Z14099
Z14098
Z14097
...
Z13099
Z13098
...
Z13001
Run Code Online (Sandbox Code Playgroud)
我试过了,但顺序不对。
select *
from table
order by
case
when Kod like 'Z15%' then 1
when Kod like 'B%' then 2
when Kod like 'C%' then 3
when Kod like 'D%' then 4
when Kod like 'E%' then 5 else 6 end asc, Kod asc
, case when Kod NOT LIKE 'B%'
AND Kod NOT LIKE 'C%'
AND Kod NOT LIKE 'D%'
AND Kod NOT LIKE 'E%'
AND Kod NOT LIKE 'Z15%' then 6
end desc
Run Code Online (Sandbox Code Playgroud)
我如何在 SQL Server 中执行此操作?
如果您对重复运行这种排序或在更大的数据集上运行感兴趣,您可能需要考虑添加一个关键表来控制排序顺序,并加入该表。
首先,我们设置测试环境:
USE tempdb;
CREATE TABLE dbo.K
( KOD VARCHAR(255) NOT NULL CONSTRAINT PK_K
PRIMARY KEY CLUSTERED
);
CREATE TABLE dbo.KSort
(
KODSort INT NOT NULL CONSTRAINT PK_KSort
PRIMARY KEY CLUSTERED
, KODPrefix VARCHAR(255) NOT NULL
);
INSERT INTO dbo.K (KOD)
VALUES ('Z15001')
, ('Z15002')
, ('B001' )
, ('B002' )
, ('C001' )
, ('C002' )
, ('Z14099')
, ('Z14098')
, ('Z14097')
, ('Z13099')
, ('Z13098')
, ('Z13001');
INSERT INTO dbo.KSort(KODSort, KODPrefix)
VALUES (10, 'Z15%')
, (20, 'B%')
, (30, 'C%')
, (40, 'Z14%')
, (50, 'Z13%');
SELECT K.*
FROM dbo.K;
Run Code Online (Sandbox Code Playgroud)
这显示了预期的结果,恰好按聚类键的顺序排序:

现在,有两个查询,第一个使用标准ORDER BY子句“手动”对结果进行排序。
SELECT *
FROM dbo.K
ORDER BY
CASE
WHEN Kod LIKE 'Z15%' THEN 1
WHEN Kod LIKE 'B%' THEN 2
WHEN Kod LIKE 'C%' THEN 3
WHEN Kod LIKE 'Z14%' THEN 4
WHEN Kod LIKE 'Z13%' THEN 5
ELSE 6
END ASC;
Run Code Online (Sandbox Code Playgroud)
为此的计划是:

好看又简单。“排序”操作符占用了计划成本的 77.6%。
如果我们使用 JOIN 来完成我们的排序,就像这样:
SELECT K.*
FROM dbo.K
INNER JOIN dbo.KSort ON K.KOD LIKE KSort.KODPrefix
ORDER BY KSort.KODSort, K.KOD;
Run Code Online (Sandbox Code Playgroud)
我们从一段更简单的代码开始,它在深层次上吸引了我;但是我们也看到了一个有趣的执行计划:

我们现在有几个嵌套循环连接,而不是排序运算符。
在处理少量数据时,一旦我们在 SQL Server 的缓冲区中有数据,差异就无关紧要。
但是,让我们看看当我们向KOD表中添加更多行时会发生什么。
TRUNCATE TABLE dbo.K;
INSERT INTO dbo.K(KOD)
SELECT TOP(1000000) CASE ROW_NUMBER() OVER (ORDER BY o.object_id) % 5
WHEN 0 THEN 'Z15'
WHEN 1 THEN 'B'
WHEN 2 THEN 'C'
WHEN 3 THEN 'Z14'
WHEN 4 THEN 'Z13' END
+ CONVERT(VARCHAR(255), ROW_NUMBER() OVER (ORDER BY o.object_id))
FROM sys.objects o, sys.objects o1, sys.columns c;
Run Code Online (Sandbox Code Playgroud)
(以上向表中添加了 1,000,000 行)
在我的机器上,这是一个带有 16GB RAM 的 4 核 Intel I7,我看到以下SET STATISTICS IO,TIME ON;配置:
“标准”排序:
(1000000 row(s) affected)
Table 'K'. Scan count 9, logical reads 2679, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 1094 ms, elapsed time = 6463 ms.
Run Code Online (Sandbox Code Playgroud)
“加入”:
(1000000 row(s) affected)
Table 'K'. Scan count 5, logical reads 2641, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KSort'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 437 ms, elapsed time = 5475 ms.
Run Code Online (Sandbox Code Playgroud)
我在开始每个查询之前使用了 DBCC FREEPROCCACHE,多次运行的结果非常相似。通常,标准排序比 JOIN 版本慢 2 到 3 倍。
除了性能影响之外,使用我建议的键表 ( dbo.KSort) 允许您随意更改输出的排序顺序,而无需修改代码,在我看来,这是一个非常好的奖励。您只需修改KODSort列的值,以便按您喜欢的任何顺序返回结果。例如,以下UPDATE将使Z14*行显示在行之前B*:
UPDATE KSort SET KODSort = 15 WHERE KODSort = 40;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1647 次 |
| 最近记录: |