来自IN子句的元素的SQL顺序

时间:2017-02-01 02:13:48

标签: sql oracle

我有一个ITEM表,我希望返回由IN子句中通知的相同订单排序的结果。这些ID由用户通知。

今天我有这个:

SELECT * 
FROM ITEM
WHERE ITEM_ID IN (45,2,671,6)
ORDER BY CASE ITEM_ID 
  WHEN 45 THEN 0
  WHEN 2 THEN 1
  WHEN 671 THEN 2
  WHEN 6 THEN 3
END

这有效,但CASElimit个65535个参数,当我需要更多时,它会给我ORA-00939: too many arguments for function

是否有针对Oracle的替代解决方案,没有限制,最好具有良好的性能,并且在其他DBMS中也可以接受?

由于

3 个答案:

答案 0 :(得分:1)

元素来自哪里?我建议您使用join

SELECT i.* 
FROM ITEM i JOIN
     (SELECT 45 as id, 1 as ord FROM DUAL UNION ALL
      SELECT 2 as id, 2 as ord FROM DUAL UNION ALL
      SELECT 671 as id, 3 as ord FROM DUAL UNION ALL
      SELECT 6 as id, 4 as ord FROM DUAL
     ) x
     ON i.ITEM_ID = x.id
ORDER BY x.ord;

如果id来自包含相关信息的表格,这会更简单。

答案 1 :(得分:1)

虽然您的逻辑和上述解决方案适用于小规模,但如果您谈论超过65000项,则需要一个可扩展的解决方案。

我的建议是将此任务分为两步。

第1步

创建一个临时表, 这个临时表将有3列最小值

TEMP_ITEM_ORDER_TABLE (
  session_key varchar2(50),
  item_id number,
  item_report_order number
)

每次用户订购此类查询时,都会将数据(即项目ID及其序列号)插入此临时表中,并使用一些唯一键来标识用户会话(可能是用户ID或会话ID)。这个技巧是为了避免多个用户同时触发报告时项目列表发生冲突。

第2步

现在触发您的报表查询加入主表,临时表与session_key。在基于输入顺序的查询顺序数据中(已存储在临时表中)

SELECT 
  T1.* , T2.item_report_order
FROM ITEM T1, TEMP_ITEM_ORDER_TABLE T2
  WHERE T1.ITEM_ID = T2.ITEM_ID
  AND T2.session_key = :input_session_key
  ORDER BY t2.item_report_order

此方法

  1. 数据库不可知
  2. 可以使用任意数量的输入进行扩展
  3. 提供最佳表现
  4. 注意:为了进一步提高查询性能,在session_key上创建索引,临时表中的item_id也在ITEM表上的item_id上创建索引(如果尚未存在)

    编辑: Oracle提供Global Temporary Table功能,该功能创建的功能只允许在会话中进行记录,并在会话提交/结束时自动清理等。您可以使用此功能并避免会话密钥,但此解决方案不能复制到其他数据库产品上,除非它们支持类似功能。

答案 2 :(得分:0)

您无需创建临时表,而是可以使用集合:

SELECT i.*
FROM   ITEM i
       INNER JOIN
       (
         SELECT ROWNUM AS rn,
                COLUMN_VALUE AS value
         FROM   TABLE( :your_array )
       ) v
       ON ( i.ITEM_ID = v.VALUE )
ORDER BY v.RN;

它甚至可以作为C# MVC pass data from one action method to another传递:

type=button