更容易限制SELECT子查询中的行?

时间:2018-01-10 19:27:46

标签: sql oracle

我在Oracle数据库上执行查询。让我们说我有一张桌子,人。每个人可以有多个参考号。参考编号存储在不同的表REFERENCENUMBERS中。

REFERENCENUMBERS包含一列PERSON_ID,它与PEOPLE表的ID列相同。通过此ID可以将表连接起来。

我想说我想在PEOPLE表上执行查询。但是我只希望每个人记录返回一个参考号:即如果一个人有多个参考号,我不希望每个参考号每人返回多行。

我选择了一个如何只选择一个参考号的标准:最早创建的参考号。创建参考号的日期作为DATECREATED存储在REFERENCENUMBERS表中。

以下代码完成此任务:

SELECT
    PEOPLE.ID,
    PEOPLE.NAME,
    PEOPLE.AGE,
    PEOPLE.ADDRESS,
    -- Subquery to return the earliest-created reference number for this person
    (
    SELECT
        REFERENCENUMBERS.NUMBER 
    FROM
        REFERENCENUMBERS
    WHERE
        REFERENCENUMBERS.PERSON_ID = PEOPLE.ID -- Link back to the main people ID
        AND REFERENCENUMBERS.DATECREATED = 
        -- Sub-sub query simply to match the earliest date
        (
        SELECT
            MIN(R.DATECREATED) -- To ensure that only the earliest-created reference number is returned.
        FROM
            REFERENCENUMBERS R -- Give this sub-sub query an alias for the table
        WHERE
            R.PERSON_ID = PEOPLE.ID -- Link back to the main people ID
        )
    )
FROM
    PEOPLE
WHERE
    PEOPLE.AGE > 18 -- Or whatever

然而,我对你们知识渊博的SQL人员提出的问题是......有更简单的方法吗?仅仅为了找到最早的日期和限制子查询的WHERE子句而包含子子查询似乎很麻烦。

必须有一种更简单,更清洁的方法。有什么建议吗?

(顺便说一下 - 示例代码与我实际工作的内容大大简化。请不要提供能够以不同风格的JOIN等方式实质性修改我的主查询的答案 - 谢谢)。< / p>

2 个答案:

答案 0 :(得分:2)

最简单的是前n个过滤器:

select people.id
     , people.name
     , people.age
     , people.address
     , ( select referencenumbers.number
         from   referencenumbers
         where  referencenumbers.person_id = people.id
         order by referencenumbers.datecreated
         fetch first row only )
from   people
where  people.age > 18;

More details here(需要Oracle 12.1或更高版本。)

或者这个(适用于早期版本):

select people.id
     , people.name
     , people.age
     , people.address
     , ( select min(rn.person_id) keep (dense_rank first order by rn.datecreated)
         from   referencenumbers rn
         where  rn.person_id = people.id )
from   people
where  people.age > 18;

(为了便于阅读,我给了referencenumbers一个较短的别名。)

答案 1 :(得分:1)

试试这个

SELECT
    PEOPLE.ID,
    PEOPLE.NAME,
    PEOPLE.AGE,
    PEOPLE.ADDRESS,
    REFERENCENUMBERS.NUMBER 
FROM PEOPLE
JOIN REFERENCENUMBERS ON REFERENCENUMBERS.PERSON_ID = PEOPLE.ID -- Link back to the main people ID
JOIN
(
    SELECT
        R.PERSON_ID, 
        MIN(R.DATECREATED) minc -- To ensure that only the earliest-created reference number is returned.
    FROM
        REFERENCENUMBERS R -- Give this sub-sub query an alias for the table
    GROUP BY R.PERSON_ID
) t ON t.minc = REFERENCENUMBERS.DATECREATED and
       t.PERSON_ID = REFERENCENUMBERS.PERSON_ID
WHERE
    PEOPLE.AGE > 18 -- Or whatever