SELECT中的子查询:尝试移至主查询

时间:2019-07-18 09:32:42

标签: sql oracle group-by subquery

我有一个具有以下结构的查询:

SELECT
    PEOPLE.ID,
    (
    SELECT MIN(R.VALUE) KEEP (DENSE_RANK FIRST ORDER BY R.DATE_OF_CREATION)
    FROM REFERENCE_NUMBERS R
    WHERE
        R.DELETED IS NULL
        AND R.PERSON_ID(+) = PEOPLE.ID
    ) AS PRIMARY_REFERENCE_NUMBER,
    PEOPLE.NAME,
    PEOPLE.DATE_OF_BIRTH
FROM
    PEOPLE
WHERE
    PEOPLE.DELETED IS NULL
    AND PEOPLE.DATE_OF_BIRTH > TO_DATE('2000-01-01','yyyy-mm-dd')

这一点是,一个人可以有多个参考号:但是我只想为每个人返回一个参考号,而不是多行。因此,我选择了最早创建的具有最小值的参考。我使用主SELECT子句中的子查询来执行此操作。上面的代码有效。

我想看看是否可以将其移至主要查询的一部分。从逻辑上讲,我本以为应该这样:

SELECT
    PEOPLE.ID,
    MIN(R.VALUE) KEEP (DENSE_RANK FIRST ORDER BY R.DATE_OF_CREATION),
    PEOPLE.NAME,
    PEOPLE.DATE_OF_BIRTH
FROM
    PEOPLE,
    REFERENCE_NUMBERS R
WHERE
    PEOPLE.DELETED IS NULL
    AND PEOPLE.DATE_OF_BIRTH > TO_DATE('2000-01-01','yyyy-mm-dd')
    AND R.DELETED IS NULL
    AND R.PERSON_ID(+) = PEOPLE.ID

但是我得到了错误:ORA-00937: not a single-group function

根据https://www.techonthenet.com/oracle/errors/ora00937.php-我需要在主查询中使用GROUP BY语句。但是,如果我添加以下行:

GROUP BY R.VALUE

...然后我得到错误ORA-00979: not a GROUP BY expression

我觉得我快到了,但是只需要一些额外的指导即可。有人可以帮忙吗?

注意:我完全了解“新”样式的JOIN语法,并且人们倾向于建议使用此语法。但是我使用“旧式”联接是有原因的。以上只是一个最小的可验证示例。我的真实代码要复杂得多,涉及到以复杂方式连接的多个表-当涉及到这种复杂程度时,旧语法更容易理解。请尽可能提供老式语法的答案。

2 个答案:

答案 0 :(得分:0)

在您的SELECT子句中没有反对使用该子查询的内容。如果要将其移至FROM子句,请按person_id分组,以便每人获得一行,并对没有参考编号的人使用外部联接。

SELECT
  p.id,
  r.primary_reference_number,
  p.name,
  p.date_of_birth
FROM people p
LEFT JOIN
(
  SELECT person_id, MIN(value) KEEP (DENSE_RANK FIRST ORDER BY date_of_creation)
    AS primary_reference_number
  FROM reference_numbers
  WHERE deleted IS NULL
  GROUP BY person_id
) r ON r.person_id = p.id
WHERE p.deleted is null
AND p.date_of_birth > date '2000-01-01;

可以将每个人与其所有参考文献一起加入,然后汇总整个混乱情况。这会使查询看起来更简单,但是我不喜欢这种方法。您需要每人一个参考号,因此请为每个人添加一个参考号。

无论如何,这将是编写此类查询的方式:

SELECT
  p.id,
  MIN(r.value) KEEP (DENSE_RANK FIRST ORDER BY r.date_of_creation)
    AS primary_reference_number,
  p.name,
  p.date_of_birth
FROM people p
LEFT JOIN reference_numbers r ON r.person_id = p.id AND r.deleted IS NULL
WHERE p.deleted is null
AND p.date_of_birth > date '2000-01-01
GROUP BY p.id, p.name, p.date_of_birth;

Oracle强制您命名在GROUP BY子句中选择的所有非聚合列。根据SQL标准,您仅需要people.id,因为其他列在功能上都依赖于它,但是不幸的是,Oracle没有此功能。

答案 1 :(得分:0)

查询中的第二列与其他列不同步,同样按其他列分组可能会帮助您

      SELECT
      PEOPLE.ID,
      MIN(R.VALUE) KEEP (DENSE_RANK 
       FIRST ORDER BY 
       R.DATE_OF_CREATION),
         PEOPLE.NAME,
       PEOPLE.DATE_OF_BIRTH
     FROM
     PEOPLE P,
    REFERENCE_NUMBERS R
  WHERE
  PEOPLE.DELETED IS NULL
   AND PEOPLE.DATE_OF_BIRTH > 
   TO_DATE('2000-01-01','yyyy-mm-dd')
   AND R.DELETED IS NULL
  AND R.PERSON_ID(+) = PEOPLE.ID
    GROUP BY 
    P.ID, P.NAME, P.DATE_OF_BIRTH