使用ORDER BY和ROWNUM的双嵌套查询中的标识符无效

时间:2014-09-02 05:35:41

标签: sql oracle nested sql-order-by rownum

我在Oracle上,我需要在一个请求中同时使用ORDER BYROWNUM。我需要对我的内部查询进行双重嵌套,因为我想首先应用ORDER BY ,然后选择<{1}}

我的数据在最高级别由ROWNUM=1过滤。但是,我在内部查询中收到错误,因为O.ID未知标识符

我想要的是什么:

O.ID

我实现此功能的唯一方法是在中间SELECT O.INSERTDATE OrderCreateDate, -- Determine delivery date (SELECT INSERTDATE FROM ( SELECT OP2.FK_ORDER, DD.ID, DD.INSERTDATE FROM MY_DELIVERYDATE_TABLE DD JOIN MY_ORDERPOS_TABLE OP2 ON DD.FK_ORDERPOS=OP2.ID LEFT OUTER JOIN MY_ORDER_TABLE O2 ON OP2.FK_ORDER=O2.ID WHERE OP2.FK_ORDER=O.ID AND -- This gives me "Invalid identifier O.ID" DD.DELFLAG IS NULL AND OP2.DELFLAG IS NULL ORDER BY DD.CLOSED ASC, ABS(TRUNC(CURRENT_DATE-TO_DATE(TO_CHAR(DD.INSERTDATE, 'DDMMYYYY'), 'DDMMYYYY'))) ASC ) WHERE ROWNUM=1) DeliveryDate FROM MY_ORDER_TABLE O WHERE O.ID = 620; -- ID goes here! 查询的WHERE子句中进行过滤。但这当然很慢,因为内部SQL在没有过滤的情况下返回整个数据。

SELECT

如何将SELECT O.INSERTDATE OrderCreateDate, -- Determine delivery date (SELECT INSERTDATE FROM ( SELECT OP2.FK_ORDER, DD.ID, DD.INSERTDATE FROM MY_DELIVERYDATE_TABLE DD JOIN MY_ORDERPOS_TABLE OP2 ON DD.FK_ORDERPOS=OP2.ID LEFT OUTER JOIN MY_ORDER_TABLE O2 ON OP2.FK_ORDER=O2.ID WHERE DD.DELFLAG IS NULL AND OP2.DELFLAG IS NULL ORDER BY DD.CLOSED ASC, ABS(TRUNC(CURRENT_DATE-TO_DATE(TO_CHAR(DD.INSERTDATE, 'DDMMYYYY'), 'DDMMYYYY'))) ASC ) WHERE ROWNUM=1 AND FK_ORDER=O.ID) DeliveryDate -- Filtering here FROM MY_ORDER_TABLE O WHERE O.ID = 620; 传递给内部查询,或者如何重新设计此查询,同时保持O.IDORDER BY的效果。


我的最终解决方案正如Kim Berg Hansen所建议并由轮辋改进:

(我不得不使用ROWNUM而不是MIN()

MAX()

1 个答案:

答案 0 :(得分:2)

在您使用的标量子查询中,您只能引用&#34; main&#34;中的表格。查询&#34;一个嵌套级别&#34;,而不是任何进一步向下,如您所见。 (我相信这个限制在版本12中解除了,所以也许你可以升级你的数据库?; - )

在标量子查询中,您尝试根据您的顺序获取第一行的INSERTDATE列的值。这也可以在没有嵌套的情况下编写如下:

SELECT
O.INSERTDATE OrderCreateDate,

-- Determine delivery date
(SELECT MAX(DD.INSERTDATE) KEEP (
          DENSE_RANK FIRST ORDER BY
          DD.CLOSED ASC, ABS(TRUNC(CURRENT_DATE-TO_DATE(TO_CHAR(DD.INSERTDATE, 'DDMMYYYY'), 'DDMMYYYY'))) ASC
        )
   FROM MY_DELIVERYDATE_TABLE DD
   JOIN MY_ORDERPOS_TABLE OP2 ON DD.FK_ORDERPOS=OP2.ID
   LEFT OUTER JOIN MY_ORDER_TABLE O2 ON OP2.FK_ORDER=O2.ID
   WHERE OP2.FK_ORDER=O.ID AND -- This will no longer give "Invalid identifier O.ID"
         DD.DELFLAG IS NULL AND OP2.DELFLAG IS NULL
) DeliveryDate

FROM MY_ORDER_TABLE O
WHERE O.ID = 620; -- ID goes here!

KEEP(DENSE_RANK FIRST告诉MAX函数,它应该在ORDER BY子句中计算那些排在 first 的行的 。所以如果你的ORDER BY是&#34;唯一&#34;,MAX只会应用于一个行。如果您的ORDER BY不是&#34;唯一&#34;并且可能有重复项,您可能会考虑是否你想要MAX或MIN(或者向ORDER BY添加一些东西以使其唯一。)

(如果您使用的是Oracle版本12,则替代KEEP(DENSE_RANK技巧将使用SELECT语句的FIRST 1 ROW ONLY子句。)