工作中的问题~按着枚举类型的字段进行排序

本文探讨了在.NET环境下,如何对枚举类型的集合进行排序,并通过实例展示了枚举值转换为整型的过程及应用。

如果一个类中,有一个属性的类型是枚举型,那么,如果我们建立了一个类的集合对象,如List<类>,那我要根据它枚举值进行排序,如何进行?

事实上.net把枚举和整型自动给我们进行了一个转换,如果要排序枚举,我们可以理解成排序整型字段,没有任何分别,如果枚举没有赋值,那么.net 运行时会根据枚举元素出现的顺序进行排序,第1个元素的值为0,依次向下加1

看这个实例代码:

 enum Example
    {
        hihi ,
        ok ,
        yes ,
        good ,
        bad ,
    }
    class exam
    {
        public Example Example { get; set; }
    }

赋值并排序,然后输出:

            List<exam> e = new List<exam>();
            foreach (string i in Enum.GetNames(typeof(Example)))
                e.Add(new exam { Example = (Example)Enum.Parse(typeof(Example), i) });
 
            e = e.AsQueryable().OrderByDescending(i => i.Example).ToList();
 
            e.ForEach(i => { Console.WriteLine("枚举名称是:{0}它的值是:{1}",i.Example,(int)i.Example); });
<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`(避免多次表扫描)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值