如何按 Oracle SQL IN() 子句中的值顺序对结果数据进行排序

Posted

技术标签:

【中文标题】如何按 Oracle SQL IN() 子句中的值顺序对结果数据进行排序【英文标题】:How to order the result data by the order of values in an Oracle SQL IN() clause 【发布时间】:2016-12-19 10:46:28 【问题描述】:

当 SQL 返回结果时,我们需要按照将值传递给 SQL 的 IN() 子句的确切顺序对它们进行排序。

查询和结果:(HR 架构)

select EMPLOYEE_ID, FIRST_NAME
from EMPLOYEES
where EMPLOYEE_ID in ('151','149','145','147','155');

EMPLOYEE_ID FIRST_NAME         
----------- --------------------
        145 John                
        147 Alberto             
        149 Eleni               
        151 David               
        155 Oliver              

但我们需要它们按 '151','149','145','147','155' 的顺序排列

预期输出

EMPLOYEE_ID FIRST_NAME         
----------- --------------------
        151 David               
        149 Eleni               
        145 John                
        147 Alberto             
        155 Oliver              

mysql 中,有 FIELD() 函数。 如何在 Oracle 中实现这一点?

【问题讨论】:

【参考方案1】:

在 Oracle 中,您可以在 PL/SQL 中编写自己的字段函数,也可以使用标准 SQL 的CASE WHEN

select EMPLOYEE_ID, FIRST_NAME
from EMPLOYEES
where EMPLOYEE_ID in ('151','149','145','147','155')
order by case EMPLOYEE_ID 
  when '151' then 1
  when '149' then 2
  when '145' then 3
  when '147' then 4
  when '155' then 5;

这是一个派生表的替代方案:

select EMPLOYEES.EMPLOYEE_ID, EMPLOYEES.FIRST_NAME
from EMPLOYEES
join
(
  select '151' as EMPLOYEE_ID, 1 as POS from DUAL
  union all
  select '149' as EMPLOYEE_ID, 2 as POS from DUAL
  union all
  select '145' as EMPLOYEE_ID, 3 as POS from DUAL
  union all
  select '147' as EMPLOYEE_ID, 4 as POS from DUAL
  union all
  select '155' as EMPLOYEE_ID, 5 as POS from DUAL
) IDS ON IDS.EMPLOYEE_ID = EMPLOYEES.EMPLOYEE_ID
order by IDS.POS;

【讨论】:

【参考方案2】:

假设列表中的值是唯一的

select      e.EMPLOYEE_ID,e.FIRST_NAME

from                EMPLOYEES e

            join    (select  rownum as n,column_value as EMPLOYEE_ID 
                     from    table (SYS.ODCIVARCHAR2LIST ('151','149','145','147','155')) t
                    ) t  

            on      t.EMPLOYEE_ID =
                    e.EMPLOYEE_ID

order by    t.n

+-------------+------------+
| EMPLOYEE_ID | FIRST_NAME |
+-------------+------------+
| 151         | David      |
+-------------+------------+
| 149         | Eleni      |
+-------------+------------+
| 145         | John       |
+-------------+------------+
| 147         | Alberto    |
+-------------+------------+
| 155         | Oliver     |
+-------------+------------+

【讨论】:

【参考方案3】:

一种方法可能是使用提供顺序的属性来构建您的列表,并将其与您的表一起用于 JOIN。 例如:

with yourList(EMPLOYEE_ID, position) as (
    select '151', 1 from dual union all
    select '149', 2 from dual union all
    select '145', 3 from dual union all
    select '147', 4 from dual union all
    select '155', 5 from dual
)
select EMPLOYEE_ID, FIRST_NAME
from EMPLOYEES inner join yourList using(EMPLOYEE_ID)
order by position;

如果您想在列表更改时限制要编写的代码,您可以通过拆分字符串来构建您的列表:

with yourList(EMPLOYEE_ID, position) as (
    SELECT regexp_substr(stringList, '[^,]+', 1, level), level
      FROM (select '151,149,145,147,155' as stringList from dual)
      CONNECT BY instr(stringList, ',', 1, level - 1) > 0
)
select EMPLOYEE_ID, FIRST_NAME
from EMPLOYEES inner join yourList using(EMPLOYEE_ID)
order by position;

通过这种方式,您只需编辑您的 ID 列表,无需对您的查询进行其他修改。

【讨论】:

以上是关于如何按 Oracle SQL IN() 子句中的值顺序对结果数据进行排序的主要内容,如果未能解决你的问题,请参考以下文章

ORDER BY 子句“IN()”中指定的值,但在泛型 SQL 和 Informix 中

Oracle 12c - 根据不同表中的值动态生成 where 子句

按mysql中select语句“in”子句中的值顺序排序

oracle数组 拼到sql的in子句中去

使用列表中的in子句加入oracle [重复]

IN子句中的Spark sql限制