【问题标题】:Keep order from 'IN' clause保持'IN'子句的顺序
【发布时间】:2012-12-17 21:00:56
【问题描述】:

是否可以保持'IN'条件子句的顺序?

我在 SO 上找到了this question,但在他的示例中,OP 已经有一个排序的“IN”子句。

我的情况不同,'IN' 子句的顺序是随机的 像这样:

SELECT SomeField,OtherField
FROM TestResult 
WHERE TestResult.SomeField IN (45,2,445,12,789)

我想以 (45,2,445,12,789) 的顺序检索结果。我正在使用 Oracle 数据库。也许SQL中有一个属性可以与条件子句一起使用来指定保持子句的顺序。

【问题讨论】:

  • 我删除了对 PL/SQL 的引用。 PL/SQL 用于存储过程、函数和触发器。其他一切都是 Oracle 中的“只是”SQL。
  • @Rikesh 可以提供帮助,但大多数答案都基于 FIELD()。好像是“MySql函数”

标签: sql oracle


【解决方案1】:

除非您使用 ORDER BY 子句,否则不会有可靠的排序..

SELECT SomeField,OtherField
FROM TestResult 
WHERE TestResult.SomeField IN (45,2,445,12,789)
order by case TestResult.SomeField
         when 45 then 1
         when 2  then 2
         when 445 then 3
         ...
         end

您可以将查询拆分为 5 个查询联合在一起...

SELECT SomeField,OtherField
FROM TestResult 
WHERE TestResult.SomeField = 4
union all
SELECT SomeField,OtherField
FROM TestResult 
WHERE TestResult.SomeField = 2
union all
...

我更相信前一种方法,而且它可能会表现得更好。

【讨论】:

  • 如您所说,除非您提供ORDER BY 子句,否则没有定义的顺序。对于UNION ALL 分隔的SELECTs 序列和其他任何地方都是如此。
  • 是的,我认为对于那些依赖于集合处理顺序的人来说,未来可能会有一个清算日(或清算日),就像那些依赖于 GROUP BY 中的隐式排序的人一样。
  • 更新:版本 12 可以并行执行集合,因此没有隐式执行顺序。
【解决方案2】:

解码函数在这种情况下会派上用场,而不是 case 表达式

SELECT SomeField,OtherField
FROM TestResult 
WHERE TestResult.SomeField IN (45,2,445,12,789)
ORDER BY DECODE(SomeField, 45,1, 2,2, 445,3, 12,4, 789,5)

请注意,出于可读性原因,value,position 对(例如 445,3)保持在一起。

【讨论】:

  • 与 Oracle 配合得很好。
【解决方案3】:

试试这个:

SELECT T.SomeField,T.OtherField
FROM TestResult T
 JOIN 
   (
     SELECT 1 as Id, 45 as Val FROM dual UNION ALL
     SELECT 2, 2 FROM dual UNION ALL
     SELECT 3, 445 FROM dual UNION ALL
     SELECT 4, 12 FROM dual UNION ALL
     SELECT 5, 789  FROM dual
   ) I
   ON T.SomeField = I.Val
ORDER BY I.Id

【讨论】:

  • 感谢@Hamlet Hakobyan。但我不需要子选择中的“FROM”关键字?就在 UNION ALL 之前?..
  • FROM clause 指定数据来源。您在子查询中有任何来源吗?没有。
  • 由于指定的数据库是Oracle,这不应该有from dual吗?
  • 它对我不起作用。我在想一个 from 是强制性的(当没有数据源时是 FROM DUAL)。
【解决方案4】:

还有一个使用字符串函数的替代方法:

with const as (select ',45,2,445,12,789,' as vals)
select tr.*
from TestResult tr cross join const
where instr(const.vals, ','||cast(tr.somefield as varchar(255))||',') > 0
order by instr(const.vals, ','||cast(tr.somefield as varchar(255))||',')

我提供这个是因为您可能会发现维护一串值比维护中间表更容易。

【讨论】:

  • 好的。但是可能会很慢。
  • @HamletHakobyan 。 . .不必要。连接有开销,在许多情况下,字符串操作可能会执行得更好。显然,如果您有包含数千个元素的列表,那么数据库应该使用连接做得更好。但对于少数人来说,字符串操作很有可能实际上会更快。
  • 问题不在列表中。在您的情况下,引擎无法使用where clause 的索引。
  • @HamletHakobyan 。 . .是的,如果你在这个字段上有一个索引。
【解决方案5】:

我能够使用(使用 SQL Server 2016)在我的应用程序中执行此操作

select ItemID, iName
  from Items
      where ItemID in (13,11,12,1)
      order by CHARINDEX(' ' + Convert("varchar",ItemID) + ' ',' 13 , 11 , 12 , 1 ')

我使用代码端正则表达式将\b(单词边界)替换为空格。有点像...

var mylist = "13,11,12,1";
var spacedlist = replace(mylist,/\b/," ");

重要的是,因为我可以在我的场景中缓存结果,直到下一次更新相关项目时,查询仅在项目创建/修改时运行,而不是在每个项目查看时运行,有助于最大限度地减少任何性能下降。

【讨论】:

    猜你喜欢
    • 2011-08-31
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    • 2014-09-10
    • 2018-04-12
    相关资源
    最近更新 更多