将TOP 1相关子查询从SQL Server转换为Oracle

时间:2013-02-11 08:17:02

标签: sql oracle11gr2 correlated-subquery rownum

如何在Oracle中执行基于ORDER BY子句返回第一个匹配行的相关子查询?我正在尝试从执行此操作的SQL Server转换查询。

为了记录,我需要坚持(主要)SQL-92语法。根本不应该使用分析函数,我需要尽量减少使用非标准SQL。 TOP 1 ... ORDER BY是SQL Server专有的,我正在努力将其翻译为rownum

注意:已经指出此特定查询不需要TOP/LIMIT/rownum,因为它在语义上等同于使用Min(),因为我们只需要一列。但我仍然会欣赏并会奖励任何有关如何执行翻译的帮助 - 因为我想更好地学习Oracle。

这是SQL Server查询(以及SqlFiddle for it):

SELECT
  D.StartDate,
  (
    SELECT TOP 1 E.EndDate
    FROM dbo.Dates E
    WHERE
      E.EndDate >= D.EndDate
      AND NOT EXISTS (
        SELECT *
        FROM dbo.Dates E2
        WHERE
          E.StartDate < E2.StartDate
          AND E.EndDate > E2.StartDate
      )
    ORDER BY
      E.EndDate,
      E.StartDate DESC
  ) EndDate
FROM
  dbo.Dates D
WHERE
  NOT EXISTS (
    SELECT *
    FROM dbo.Dates D2
    WHERE
      D.StartDate < D2.EndDate
      AND D.EndDate > D2.EndDate
  );

这是我尝试过的。我受到了阻碍,因为我在D.EndDate外部参考上收到错误。

  

ORA-00904:“D”。“ENDDATE”:标识符无效

但是问题是什么? SELECT子句中的相关子查询应该可以访问所有外部表数据。我不知道下一步该往哪里去。 (和the SqlFiddle for this)。

SELECT
  D.StartDate,
  (
    SELECT *
    FROM (
      SELECT E.EndDate
      FROM Dates E
      WHERE
        E.EndDate >= D.EndDate
        AND NOT EXISTS (
          SELECT *
          FROM Dates E2
          WHERE
            E.StartDate < E2.StartDate
            AND E.EndDate > E2.StartDate
        )
      ORDER BY
        E.EndDate,
        E.StartDate DESC
    )
    WHERE rownum = 1
  ) EndDate
FROM
  Dates D
WHERE
  NOT EXISTS (
    SELECT *
    FROM Dates D2
    WHERE
      D.StartDate < D2.EndDate
      AND D.EndDate > D2.EndDate
  );

1 个答案:

答案 0 :(得分:1)

我可能会遗漏某些内容,但您不能使用MIN代替TOP 1 ... ORDER BY,因为您通过EndDate,StartDate DESC订购,并且只选择EndDate,开始日期与排序,只有当你有2个结束日期相同时才考虑它,但由于你只选择结束日期,所以使用两个(或更多结束日期)中的哪一个并不重要:

SELECT  D.StartDate,
        (   SELECT  MIN(E.EndDate)
            FROM    Dates E
            WHERE   E.EndDate >= D.EndDate
            AND     NOT EXISTS 
                    (   SELECT  1
                        FROM    Dates E2
                        WHERE   E.StartDate < E2.StartDate
                        AND     E.EndDate > E2.StartDate
                    )
        ) EndDate
FROM    Dates D
WHERE   NOT EXISTS 
        (   SELECT  1
            FROM    Dates D2
            WHERE   D.StartDate < D2.EndDate
            AND     D.EndDate > D2.EndDate
        );

<强> Example on SQL Fiddle