【问题标题】:Does querying by array input guarantee results will be in same order by default?默认情况下,按数组输入查询保证结果的顺序相同吗?
【发布时间】:2023-01-19 21:20:31
【问题描述】:

我有一个采用 PL/SQL 关联数组值输入的存储过程,如下所示:

TYPE IntegerArray is table of Number index by binary_integer;
PROCEDURE GetItems(itemIds in IntegerArray, results out sys_refcursor)
IS BEGIN
Open Results for
select id, name, price from Item where id in (select * from table(itemIds));
END;

它是从 C# 调用的,输入项 ID 按特定顺序排列,应保留在输出中。 我能够编写 C# 代码,它将根据输入 List<int> ids 对结果对象数组 List<(int id,string name,int price)> data 进行排序,因为存在 1:1 映射输入 - 输出,但我无法判断是否我需要to,否则 Oracle 将根据输入自动按顺序返回行。这有保证吗?甲骨文甚至输入中的排序概念?

【问题讨论】:

  • 如果 SELECT 语句中没有 ORDER BY 子句,则无法保证数据将以任何特定顺序返回。它是关于关系数据库的;表格中的行没有任何顺序(通常,它被比作装满苹果的篮子——哪个苹果是“第一个”?)。因此,以所需顺序返回行的唯一方法是应用 ORDER BY 子句。
  • @Littlefoot 这个过程不知道顺序,它是由输入定义的....我认为这回答了我的问题,调用 C# 代码将要需要处理订购。我什至不确定 PL/SQL 关联数组是否对 Oracle 有排序。如果这是答案,请随时提供
  • 我有点惊讶你没有收到错误PL/SQL: ORA-22905: cannot access rows from a non-nested table item。据我所知,select * from table(itemIds) 仅适用于嵌套表,即没有 index by binary_integer 子句。
  • @WernfriedDomscheit 是的。我让这个工作但我不确定为什么 - 我期待需要基于 SO 答案的额外步骤但是然后它运行所以我停止寻找!
  • 通常 PL/SQL 关联数组中的项目是有序的,请参阅PL/SQL Collections and Records:“索引按排序顺序存储,而不是创建顺序。对于字符串类型,排序顺序由初始化参数 NLS_SORT 和 NLS_COMP 确定。" 但是,通过使用 SELECT,订单变得不确定。

标签: oracle plsql


【解决方案1】:

如果您有一个在 SQL 中定义的嵌套表集合类型(您没有,请参见下文):

CREATE TYPE IntegerList is table of Number;

然后你就可以在SQL语句中使用它了。

当你这样做时:

SELECT * FROM TABLE(instance_of_integer_list)

然后经验证据表明它将按顺序返回集合中的值。

(注意:这不能保证,因为当结果集没有 ORDER BY 子句时,它们是非确定性排序的,并且可能存在这样的情况,例如并行数据库上的大数组,其中小数组在单个数据库上的经验证据数据库实例不成立,订单可能无法维持。)

然而:

SELECT id, name, price
FROM   Item
WHERE  id IN (SELECT * FROM TABLE(instance_of_integer_list));

不保证外部查询的任何特定顺序。

如果您想根据集合的顺序对外部查询进行排序,则需要使用 JOINORDER BY 子句:

SELECT i.id, i.name, i.price
FROM   Item i
       INNER JOIN (
         SELECT COLUMN_VALUE AS item,
                ROWNUM AS position
         FROM   TABLE(instance_of_integer_list)
       ) t
       ON i.id = t.item
ORDER BY t.position;

你做不是具有嵌套表集合类型(并且 C# 不支持传递嵌套表集合类型,它仅支持 PL/SQL 关联数组类型)。

您应该需要将 PL/SQL 关联数组集合转换为 SQL 嵌套表集合,以便能够在 SQL 中使用它:

CREATE PACKAGE your_package IS
  TYPE IntegerArray IS TABLE OF NUMBER INDEX BY binary_integer;

  FUNCTION map_ids(
    Ids     IN  IntegerArray
  ) RETURN IntegerList PIPELINED;

  PROCEDURE GetItems(
    ItemIds IN  IntegerArray,
    results OUT SYS_REFCURSOR
  );
END;
/

CREATE PACKAGE BODY your_package IS
  FUNCTION map_ids(
    Ids     IN  IntegerArray
  ) RETURN IntegerList PIPELINED
  IS
    v_idx BINARY_INTEGER;
  BEGIN
    IF ids IS NULL THEN
      RETURN;
    END IF;
    v_idx := ids.FIRST;
    WHILE v_idx IS NOT NULL LOOP
      PIPE ROW(ids(v_idx));
      v_idx := ids.NEXT(v_idx);
    END LOOP;
  END;

  PROCEDURE GetItems(
    ItemIds IN  IntegerArray,
    results OUT SYS_REFCURSOR
  )
  IS
  BEGIN
    OPEN Results FOR
      SELECT i.id, i.name, i.price
      FROM   Item i
             INNER JOIN (
               SELECT COLUMN_VALUE AS item,
                      ROWNUM AS position
               FROM   TABLE(map_ids(ItemIds))
             ) t
             ON i.id = t.item
      ORDER BY t.position;
  END;
END;
/

然后,如果关联数组对其键排序的顺序对应于您要显示数据的顺序,那么它应该工作(注意:这是未经测试的,因为我没有你的数据、表格或 C# 应用程序来调用包).

【讨论】:

  • 您还可以从 map_ids 返回一个 RECORD(idx, id),这样您就不必使用 rownum 加入子选择,idx 将设置为 PIPE 循环的 v_idx。
猜你喜欢
  • 2014-09-08
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
相关资源
最近更新 更多