【问题标题】:How to use order by and rownum without subselect?如何在没有子选择的情况下使用 order by 和 rownum?
【发布时间】:2014-10-08 16:05:59
【问题描述】:

我需要使用 order by 和 rownum 构建查询,但不使用 sublect。 需要对查询的第一行进行排序。

换句话说,我想要的结果

select * from (
SELECT CAMP1,ORDERCAMP
FROM TABLENAME
ORDER BY ORDERCAMP) where rownum=1;

但不使用子选择。有可能吗?

我有一个 Oracle 11。你可以说这是我的全部查询:

SELECT T1.CAMP_ID,
  T2.CAMP
  (SELECT OT.CAMP
  FROM OTHERTABLE OT
  WHERE OT.FK_TO_TABLE1=T1.CAMP_ID
  ORDER BY OT.ORDERCAMP
  )
FROM TABLE1 T1,
  TABLE2 T2
WHERE T1.FK_TO_T2=T2.PK;

子查询返回多行,我不能使用另一个子查询,例如

SELECT T1.CAMP_ID,
  T2.CAMP
  (SELECT *
  FROM
    (SELECT OT.CAMP
    FROM OTHERTABLE OT
    WHERE OT.FK_TO_TABLE1=T1.CAMP_ID
    ORDER BY OT.ORDERCAMP
    )
  WHERE ROWNUM=1
  )
FROM TABLE1 T1,
  TABLE2 T2
WHERE T1.FK_TO_T2=T2.PK;
SELECT CAMP1,ORDERCAMP FROM TABLE2 ORDER BY ORDERCAMP

因为T1.CAMP_ID 在第三级子查询中是无效标识符。

我希望我已经对自己进行了足够的解释。

【问题讨论】:

  • 您使用的是哪个版本?为什么不想使用子查询?这是您正在使用的工具的练习还是限制?出于您的目的,CTE 是否算作子查询?
  • 嗨,我有一个 Oracle 11。我不能使用子查询,因为这个选择已经是一个子选择
  • 您可以嵌套子查询,除非您有一个连接条件或过滤器引用了链上太远的东西。在不完全了解您要解决的问题的情况下(最好使用可重现的示例),很难提出合适的解决方案。简短的回答是你不能,所以你需要一种不同的方法。
  • 嗨,Alex,我们可以说这是我的完整查询:SELECT T1.CAMP_ID, T2.CAMP (SELECT OT.CAMP FROM OTHERTABLE OT WHERE OT.FK_TO_TABLE1=T1.CAMP_ID ORDER BY OT.ORDERCAMP) FROM TABLE1 T1, TABLE2 T2 WHERE T1.FK_TO_T2=T2.PK; 子查询返回多于 1 行,这就是为什么我只想恢复第一行
  • @AlexPoole 我已编辑问题以添加更多信息

标签: sql oracle sql-order-by rownum


【解决方案1】:

您当前的查询(没有无效的ORDER BY)得到ORA-01427: single-row subquery returns more than one row。可以嵌套子查询,但加入时只能回溯一级;所以如果你这样做了:

SELECT T1.CAMP_ID, T2.CAMP,
  (SELECT CAMP FROM
  FROM
    (SELECT OT.CAMP
    FROM OTHERTABLE OT
    WHERE OT.FK_TO_TABLE1=T1.CAMP_ID
    ORDER BY OT.ORDERCAMP
    )
  WHERE ROWNUM = 1)
FROM TABLE1 T1, TABLE2 T2 WHERE T1.FK_TO_T2=T2.PK;

...然后你会得到ORA-00904: "T1"."CAMP_ID": invalid identifier。因此,大概是您的问题。

您可以改为加入第三个表,并使用解析 ROW_NUMBER() 函数分配行号,然后使用围绕整个事物的外部选择仅查找具有最低 @987654329 的记录@:

SELECT CAMP_ID, CAMP, OT_CAMP
FROM (
  SELECT T1.CAMP_ID, T2.CAMP, OT.CAMP AS OT_CAMP,
    ROW_NUMBER() OVER (PARTITION BY T1.CAMP_ID ORDER BY OT.ORDERCAMP) AS RN
  FROM TABLE2 T2
  JOIN TABLE1 T1 ON T1.FK_TO_T2=T2.PK
  JOIN OTHERTABLE OT ON OT.FK_TO_TABLE1=T1.CAMP_ID
)
WHERE RN = 1;

ROW_NUMBER() 可以根据 T1.CAMP_ID 主键值或其他任何唯一值进行分区。

SQL Fiddle demo,包括独立运行的内部查询,因此您可以看到在应用外部过滤器之前分配的RN 编号。

另一种方法是使用聚合KEEP DENSE_RANK FIRST function

SELECT T1.CAMP_ID, T2.CAMP,
  MAX(OT.CAMP) KEEP (DENSE_RANK FIRST ORDER BY OT.ORDERCAMP) AS OT_CAMP
FROM TABLE2 T2
JOIN TABLE1 T1 ON T1.FK_TO_T2=T2.PK
JOIN OTHERTABLE OT ON OT.FK_TO_TABLE1=T1.CAMP_ID
GROUP BY T1.CAMP_ID, T2.CAMP;

这有点短,不需要内部查询。我不确定其中一个是否有任何真正的优势。

SQL Fiddle demo。

【讨论】:

  • 嗨@Alex Poole。我有类似的问题需要帮助
  • @Aradhya - 如果这不能解决您的问题,那么您需要提出一个新问题,解释您尝试过的内容以及遇到的问题。
【解决方案2】:

在最新版本的 Oracle 中,您可以:

SELECT CAMP1, ORDERCAMP
FROM TABLENAME
ORDER BY ORDERCAMP
FETCH FIRST 1 ROWS ONLY;

否则,我认为您需要某种子查询。

【讨论】:

  • @Angel 。 . .我认为它是在 Oracle 12 中引入的。
【解决方案3】:

您可以使用 LIMIT 或 SELECT TOP 1 SELECT CAMP1, ORDERCAMP FROM TABLENAME ORDER BY ORDERCAMP LIMIT 1

【讨论】:

  • 这两种语法都不是 Oracle 的有效语法。即使在 12c 中,Gordon 也展示了这一点。
猜你喜欢
  • 1970-01-01
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2016-04-21
  • 2011-10-12
  • 2011-06-10
  • 1970-01-01
  • 2013-12-07
相关资源
最近更新 更多