SQL中按中文字段排序

名称

类型

长度

允许为空

/外键、索引

默认值

备注

TaskSortID

Int

 

Not null

Primary key

Identity(1,1)

 

Type

Int

 

Not null

 

 

分类所属类别  1=客户任务 2=客户投诉 4=内部任务

Father

Int

 

Not null

 

0

上一级分类ID

SortName

Varchar

20

 

 

 

分类名称

IsUsed

Tinyint

1

Not null

 

 

是否在用1= 0=否

EmployeeID

Char

3

Not null

References T_Employees(EmployeeID)

 

创建人工号

Createtime

DateTime

 

Not null

getdate()

 

创建时间

要求sortName=‘服务’和‘退货’的项依次排在最前面

select * from TS_TaskSort order by case when SortName='服务' then 0 when SortName='退货' then 1 else 2 end,CreateTime asc

----------------------------------------------------------------------------------------------------------------------------------------------------

结果:

2 1 1 服务 1 301 2010-03-23
6 2 2 服务 1 303 2010-03-23
4 4 4 退货 1 303 2010-03-23
1 1 1 订单 1 301 2010-03-23 11:22:26.950
3 2 2 发货 1 301 2010-03-23 11:25:44.403
5 4 4 发票 0 303 2010-03-23 11:26:42.000

<think> 我们要解决用户的问题:SQL中按特定字段排序的方法。根据引用内容,有几种常见方法: 1. 使用UNION ALL将不同状态的数据分别查询并排序,然后合并(如引用[1]) 2. 使用CASE WHEN表达式在ORDER BY子句中自定义排序顺序(如引用[2]、[3]、[4]、[5]) 用户的需求是:根据status字段的特定值('process','done','failure')进行排序,并且不同状态有不同的排序规则(process状态按date_created降序,done和failure按升序)。同时,同样的process状态按date_created倒序,done和failure按date_created顺序排。 引用[1]中的方法虽然可行,但是需要多次扫描表(三次SELECT),效率可能不高。而引用[2]-[5]中使用的CASE WHEN方法可以在一次查询中完成。 因此,我们可以推荐使用CASE WHEN方法,在ORDER BY子句中进行复杂的排序逻辑。 具体思路: 1. 首先,我们需要按照状态值赋予不同的排序优先级:让process排在最面,然后是failure,最后是done(或者按照用户要求的顺序:process, done, failure)。但用户没有要求状态之间的顺序,只要求了每个状态内部的排序规则,所以我们可以按照process、done、failure的顺序来排列(因为用户用UNION ALL时也是这个顺序)。 2. 然后,在同一个状态内,按照date_created进行不同的排序:process状态降序,done和failure升序。 我们可以使用两个ORDER BY条件: 第一个条件:确定状态之间的顺序(使用CASE WHEN赋予不同的数值,然后按这个数值排序)。 第二个条件:根据状态的不同,对date_created进行不同的排序(这里也需要用CASE WHEN,因为不同的状态要求不同的排序方向)。 但是,第二个条件中同时有升序和降序,我们可以这样处理: 对于需要升序的状态,我们保持date_created原值;对于需要降序的状态,我们可以对date_created取负值(如果date_created是数值类型)或者用其他方式,但更通用的方法是使用两个字段排序,或者使用CASE WHEN在每个条件下生成不同的排序值。 另一种思路(更直接): 我们可以将排序分成两个部分: 第一部分:状态优先级(process, done, failure)可以用一个CASE WHEN来定义顺序号。 第二部分:在状态内部,对于process状态,我们希望按date_created降序;对于done和failure,我们希望按date_created升序。我们可以这样: - 当状态为process时,我们用一个很大的值减去date_created(如果date_created是日期,我们可以用时间戳)来实现降序效果,但这不够通用,而且不同的数据库日期处理不同。 - 更好的方法是使用两个排序字段:第一个字段是状态优先级,第二个字段是另一个CASE WHEN,它根据不同状态返回不同的排序依据值。但是,第二个字段需要统一排序方向。 更简单且通用的方法是:在第二个排序字段上,我们分别处理升序和降序,但由于ORDER BY可以指定多个条件,我们可以这样: ORDER BY (CASE status WHEN 'process' THEN 1 WHEN 'done' THEN 2 WHEN 'failure' THEN 3 ELSE 4 END), (CASE WHEN status = 'process' THEN date_created END) DESC, (CASE WHEN status IN ('done','failure') THEN date_created END) ASC 但是,这样写可能会有问题,因为当status为process时,第二个CASE会返回date_created,第三个CASE返回NULL,而NULL排序时会集中在一起。所以,当status为process时,第一个字段是1,然后第二个字段按date_created降序,第三个字段NULL(不参与排序)。对于done状态,第一个字段是2,第二个字段NULL,第三个字段按date_created升序。failure同理。 这种写法在多个数据库中是可行的,因为每个行只会被一个CASE WHEN命中(非命中返回NULL),而NULL排序时会被忽略(不影响其他条件的排序)。 但是,用户要求同样的process状态按date_created倒序,同样的done和failure按顺序排。所以,我们可以使用这种方式。 然而,引用[1]中用户提供的UNION ALL方法虽然简单直观,但执行效率可能较低(尤其是表数据量大时,需要扫描表三次)。因此,我们更推荐使用CASE WHEN的方法。 下面我们给出使用CASE WHEN的排序方法: 排序条件: ORDER BY CASE status WHEN 'process' THEN 1 WHEN 'done' THEN 2 WHEN 'failure' THEN 3 ELSE 4 END, -- 先按状态优先级排序 CASE WHEN status = 'process' THEN date_created END DESC, -- 对process状态按date_created降序 CASE WHEN status IN ('done', 'failure') THEN date_created END ASC -- 对done和failure状态按date_created升序 注意:由于同一个记录不会同时有多个状态,所以第二个和第三个CASE WHEN不会同时生效。对于process的记录,第三个CASE WHEN会返回NULL,而NULL排序时会被忽略(不影响第一个字段和第二个字段排序)。同样,对于done和failure,第二个CASE WHEN返回NULL。 另外,我们也可以将第二个和第三个条件合并成一个表达式,但这样会复杂一些。 我们也可以用一个条件达到同样的效果,但可读性稍差: ORDER BY CASE status WHEN 'process' THEN 1 WHEN 'done' THEN 2 WHEN 'failure' THEN 3 ELSE 4 END, CASE WHEN status = 'process' THEN -UNIX_TIMESTAMP(date_created) -- 假设是MySQL,用时间戳取负,这样降序就变成了升序(因为负数越大实际时间越近) ELSE UNIX_TIMESTAMP(date_created) -- 对于done和failure,我们取正的时间戳,然后按升序排(正数小的在) END 但是这种方法依赖于数据库函数(如UNIX_TIMESTAMP),而且如果date_created不是日期类型就不行。另外,数值转换可能影响性能。 因此,我们更推荐第一种多个CASE WHEN的方法,因为它更通用,而且不需要转换类型。 所以,完整的SQL语句可以写成: ```sql SELECT * FROM 表名 ORDER BY CASE status WHEN 'process' THEN 1 WHEN 'done' THEN 2 WHEN 'failure' THEN 3 ELSE 4 END, CASE WHEN status = 'process' THEN date_created END DESC, CASE WHEN status IN ('done','failure') THEN date_created END ASC; ``` 注意:如果数据库不支持NULL值在排序中被忽略(即NULL与其他值比较时的行为),那么我们需要考虑数据库的默认行为。在标准SQL中,NULL排序在升序时排在最后,降序时排在最。但这里,由于每个行只会命中一个非NULL的CASE表达式,所以不会互相干扰。例如,对于process的记录,在第三个CASE中会返回NULL,而done和failure的记录在第二个CASE中返回NULL,所以在第二个排序字段上,done和failure的记录都是NULL,它们会排在一起(在process的记录之后),然后在第三个排序字段上,它们按照date_created升序排列。而process的记录在第二个排序字段上按date_created降序,第三个排序字段上为NULL(所以NULL都集中在一起,但此时已经按第一个字段分开了)。 因此,这个排序逻辑可以实现用户的需求。 另外,用户的需求中,同样的process状态按date_created倒序,同样的done和failure按顺序排。这里我们第一个字段已经将状态分成了三组(process一组,done一组,failure一组),然后每组内部再按第二个和第三个条件排序。由于每组只受一个非NULL条件影响,所以每组内部排序正常。 总结:我们推荐使用ORDER BY子句中使用多个CASE WHEN表达式来实现复杂的排序规则。 现在,我们给出完整回答。 </think> ### SQL按特定字段排序的方法 在SQL中实现按特定字段排序,主要有两种方法:**`UNION ALL`分段查询法**和**`CASE WHEN`表达式法**。以下是详细说明: #### 方法1:`UNION ALL`分段查询(适用于简单场景) ```sql SELECT * FROM 表名 WHERE status = 'process' ORDER BY date_created DESC UNION ALL SELECT * FROM 表名 WHERE status = 'done' ORDER BY date_created ASC UNION ALL SELECT * FROM 表名 WHERE status = 'failure' ORDER BY date_created ASC; ``` **特点**: 1. 每个`SELECT`单独处理不同状态值 2. 每个片段可自定义排序规则 3. 逻辑清晰但需多次扫描表[^1] #### 方法2:`CASE WHEN`表达式(推荐高效方案) ```sql SELECT * FROM 表名 ORDER BY CASE status WHEN 'process' THEN 1 -- 优先级最高 WHEN 'done' THEN 3 WHEN 'failure' THEN 2 -- 可自由调整顺序 ELSE 4 END, -- 先按状态优先级排序 CASE WHEN status = 'process' THEN date_created END DESC, -- process状态降序 CASE WHEN status IN ('done', 'failure') THEN date_created END ASC; -- 其他状态升序 ``` **优势**: 1. 单次查询即可完成复杂排序 2. 通过`CASE`灵活定义排序优先级 3. 支持混合排序方向(升序/降序)[^2][^3] 4. 兼容所有主流数据库(MySQL/Oracle/SQL Server等) #### 其他应用场景 1. **自定义枚举值排序**(如按status=0,3,1,2顺序): ```sql ORDER BY CASE status WHEN 0 THEN 1 WHEN 3 THEN 2 WHEN 1 THEN 3 WHEN 2 THEN 4 END ``` [^2] 2. **字段排序**(如ID以特定城市开头): ```sql ORDER BY CASE WHEN id LIKE 'shanghai%' THEN 0 WHEN id LIKE 'beijing%' THEN 1 ELSE 2 END ``` [^5] 3. **特殊值优先显示**: ```sql ORDER BY CASE WHEN state = '40' THEN 0 ELSE 1 END, -- 优先显示40 created_date DESC ``` [^3] ### 选择建议 - 简单分段 → 用`UNION ALL` - 复杂逻辑 → 用`CASE WHEN` - 性能要求高 → `CASE WHEN`(避免多次表扫描)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值