【问题标题】:ORACLE, PLSQL, Select from pre-populated set of values in WHERE IN clauseORACLE、PLSQL、从 WHERE IN 子句中预先填充的一组值中选择
【发布时间】:2014-05-29 01:03:57
【问题描述】:

简明示例和说明

我想编写一个 WHERE IN 子句,从预先填充的一组数字中进行选择

这里有一些代码。我想存储这组数字,并从中进行选择,这样我就不必重复生成这组数字的查询。

ARRAY_OF_NUMBERS = Values from some select statement


  -- SHIPMENTS CURSOR
  OPEN O_SHIPMENTS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_SHIPMENT_INFO SI
        WHERE INTERNAL_ASN IN (ARRAY_OF_NUMBERS) -- need to populate something
     ORDER BY INTERNAL_ASN;

  -- ORDER CURSOR
  OPEN O_ORDERS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_ORDER_INFO OI
        WHERE INTERNAL_ASN IN (ARRAY_OF_NUMBERS) -- need to populate something
     ORDER BY INTERNAL_ASN;

我读过一些关于使用数组的文章,但它说它必须是全局数组而不是会话级别。我不确定这是多么真实,我什至不确定全局数组是什么,但我想这需要是会话级别的,因为它会随着每个程序调用而改变。也许我可以使用一个临时表。

关于我能做到这一点的最佳方式的任何想法?

------------- 编辑 ------------ (添加详细示例)

详细示例及说明

我有 4 个位于 4 个不同层次级别的表和 4 个存储过程。每个过程都包含输入标准,以通过特定级别的标准在所有 4 个级别构建数据选择。

在此示例中,我的调用者将输入存在于纸箱级别的选择标准。然后我将使用从该选择中缩小的 INTERNAL_ASN 编号,向上移动层级并检索:ORDERS this carton is on,SHIPMENTS that ORDER is on,然后向下检索:ITEMS on this CARTON。

我注意到在升级时,我重复了相同的选择,虽然我应该以某种方式存储这组数字,所以我没有每次都重新运行选择来获取它们,但不确定如何。

      -- SHIPMENTS CURSOR
  OPEN O_SHIPMENTS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_SHIPMENT_INFO SI
        WHERE     INTERNAL_ASN IN
                     (SELECT INTERNAL_ASN
                        FROM Q194977.AN_CARTON_INFO CI
                       WHERE     (I_BOL IS NULL OR BILL_OF_LADING = I_BOL)
                             AND (   I_CARTON_NO IS NULL
                                  OR CARTON_NO = I_CARTON_NO)
                             AND (I_PO_NO = 0 OR PO_NO = I_PO_NO)
                             AND (I_STORE_NO = 0 OR STORE_NO = I_STORE_NO))
     ORDER BY INTERNAL_ASN;

  -- ORDER CURSOR
  OPEN O_ORDERS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_ORDER_INFO OI
        WHERE     INTERNAL_ASN IN
                     (SELECT INTERNAL_ASN
                        FROM Q194977.AN_CARTON_INFO CI
                       WHERE     (I_BOL IS NULL OR BILL_OF_LADING = I_BOL)
                             AND (   I_CARTON_NO IS NULL
                                  OR CARTON_NO = I_CARTON_NO)
                             AND (I_PO_NO = 0 OR PO_NO = I_PO_NO)
                             AND (I_STORE_NO = 0 OR STORE_NO = I_STORE_NO))
              AND (I_PO_NO = 0 OR PO_NO = I_PO_NO)
     ORDER BY INTERNAL_ASN;

  -- CARTONS CURSOR
  OPEN O_CARTONS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_CARTON_INFO CI
        WHERE     (I_BOL IS NULL OR BILL_OF_LADING = I_BOL)
              AND (I_CARTON_NO IS NULL OR CARTON_NO = I_CARTON_NO)
              AND (I_PO_NO = 0 OR PO_NO = I_PO_NO)
              AND (I_STORE_NO = 0 OR STORE_NO = I_STORE_NO)
     ORDER BY INTERNAL_ASN;

  -- ITEMS CURSOR
  OPEN O_ITEMS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_ITEM_INFO II
        WHERE     CARTON_NO IN
                     (SELECT CARTON_NO
                        FROM Q194977.AN_CARTON_INFO CI
                       WHERE     (I_BOL IS NULL OR BILL_OF_LADING = I_BOL)
                             AND (   I_CARTON_NO IS NULL
                                  OR CARTON_NO = I_CARTON_NO)
                             AND (I_PO_NO = 0 OR PO_NO = I_PO_NO)
                             AND (I_STORE_NO = 0 OR STORE_NO = I_STORE_NO))
     ORDER BY INTERNAL_ASN;

【问题讨论】:

  • 不确定这是否主要是术语问题。听起来您想要一个模式或数据库级别的数组类型,这意味着在 SQL 中使用create type 创建的东西,而不是在 PL/SQL 中声明的东西。然后您可以使用table() 调用而不是in。你是这个意思吗? Something like this, maybe?

标签: arrays oracle plsql set where-in


【解决方案1】:

假设您的意思是数字集合(PL/SQL 中有三种集合类型,其中一种是关联数组,但这听起来不像您想要的),您可以这样做

CREATE OR REPLACE TYPE num_tbl
    AS TABLE OF NUMBER;

然后,在你的过程中

  l_nums num_tbl;
BEGIN
  SELECT some_number
    BULK COLLECT INTO l_nums
    FROM <<your query to get the numbers>>;

  <<more code>>

  OPEN O_SHIPMENTS_CURSOR FOR
       SELECT *
         FROM Q194977.AN_SHIPMENT_INFO SI
        WHERE INTERNAL_ASN IN (SELECT column_value
                                 FROM TABLE( l_nums )) 
     ORDER BY INTERNAL_ASN;

这在语法上是有效的。然而,它是否真的对你有用是一个单独的问题。

  • 集合存储在数据库服务器上相对昂贵的 PGA 内存中。如果你在一个集合中存储了几百个数字,这可能不是一个大问题。另一方面,如果您要存储 10 或 100 MB 的数据并在多个会话中运行,那么这一段代码很容易消耗数据库服务器上许多 GB 的 RAM,从而导致许多性能问题。
  • 将大量数据从 SQL 移动到 PL/SQL,然后再返回到 SQL 从性能的角度来看也可能存在一些问题 - 将所有内容留在 SQL 中并让 SQL 引擎处理它通常更有效。
  • 如果您以这种方式使用集合,您将阻止优化器考虑以更有效的方式合并两个查询的连接顺序和查询计划。如果您确定最有效的计划是使用少量internal_asn 值来使用索引探测an_shipment_info 表,那么这可能不是主要问题。但是,如果您不确定最佳查询计划是什么,尤其是当您的实际查询比您发布的更复杂时,您可能会阻止优化器对每个查询使用最有效的计划。

您要解决的问题是什么?你谈到不想重复代码。这会让我怀疑你真的只是想要一个可以在查询中引用的视图,而不是为复杂的 SQL 语句重复代码。但这假定您要解决的问题是代码优雅,可能准确也可能不准确。

【讨论】:

  • 谢谢。起初我实际上有更多细节,并删除了它,因为我认为我的问题过于复杂了。我编辑并将其添加回底部。在此代码示例中,我通过 CARTON 级别输入标准以缩小结果范围,然后重复查询以获取 INTERNAL_ASN 编号以向上移动并获取其他级别。来自软件工程背景,我总是认为重复代码是不好的,但也许像你说的那样把它保留在 SQL 中会更好。我不知道。这个选择每次都会通过输入的内容和 lvl 改变,所以我看不到视图工作。
  • 哦,这可能是一组 1-100 的数字,所以我认为内存应该不是问题。
猜你喜欢
  • 2013-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
相关资源
最近更新 更多