Sql 限制SELECT子查询中的行的更简单方法?

Sql 限制SELECT子查询中的行的更简单方法?,sql,oracle,Sql,Oracle,我在Oracle数据库上执行查询。假设我有一张桌子,各位。每个人都可以有多个参考号。参考号存储在不同的表ReferenceNumber中 ReferenceNumber包含一列PERSON_ID,该列与PEOPLE表的ID列相同。正是通过此ID连接表 假设我想在PEOPLE表上执行查询。但是,我只希望每个人记录返回一个参考号:即,如果一个人有多个参考号,我不希望每个参考号每个人返回多行 我为如何只选择一个参考号选择了一个标准:最早创建的参考号。参考号创建日期作为DATECREATED存储在Ref

我在Oracle数据库上执行查询。假设我有一张桌子,各位。每个人都可以有多个参考号。参考号存储在不同的表ReferenceNumber中

ReferenceNumber包含一列PERSON_ID,该列与PEOPLE表的ID列相同。正是通过此ID连接表

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

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

以下代码执行此任务:

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子句而包含子查询似乎很麻烦

必须有一种更简单或更干净的方法来做到这一点。有什么建议吗

(顺便说一下,示例代码与我实际使用的代码相比大大简化了。请不要提供使用不同样式联接等实质性修改我的主要查询的答案-谢谢)。

试试这个

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

最简单的是top-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;
(需要Oracle 12.1或更高版本。)

或此(适用于早期版本):


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

为什么连接是不正确的?3个原因:首先,基本代码是由Business Objects应用程序生成的,它使用上述格式连接,编辑后我不想混淆。第二,正如我所说的,代码大大简化了我正在进行的工作,其中涉及多达10个不同的表,所有这些表都以各种方式链接。第三,我不是一个SQL专家,也不是一个非常基本的单连接的fait?是化名吗?它是如何定义的?您的第一次使用遵循MIN()计算:这只是用作该计算的别名吗?我的Oracle版本使用了“AS”这个词(例如选择PEOPLE.ID作为PERSONID)。或者你在做别的什么?我相信这两种语法都是有效的,但是是的,这是一个别名好的,谢谢大家-我会尝试看看我是否可以将它与那些连接一起工作到我的代码中(并找出它的意思:)。我会让你知道的,谢谢。正如拉尔夫提到的,“MIN(R.DATECREATED)minc”和“MIN(R.DATECREATED)AS minc”都可以用。它可以归结为编码标准和个人喜好。有些人(包括我自己)更喜欢指定AS,以明确这是一个别名。其他人不认为有必要,因为这是一个可选参数。再次感谢-我投票支持这个参数,因为我确信它会如所述工作,但是对于这些复杂的(对我来说)连接,我无法将它们应用到我实际使用的代码中(因为有太多具有复杂关系的表)。也许一位经验丰富的SQL专家能够做到这一点,但我无法理解将此应用于我实际使用的内容。但是再次谢谢,谢谢。我会试试这个-虽然我不熟悉KEEP和DENSE_RANK。我希望它能在我的甲骨文中起作用。(感谢您的编辑!)哦,添加了缺少的行。谢谢我很高兴地说,第二个“早期版本”的例子是有效的!再次感谢。我现在必须读一读关于KEEP、DENSE_RANK和FIRST的文章。据我所知,当你使用这些,它实际上并不重要,你是否使用最小或最大(如上所述)-对吗?或者错了…@ChrisMelville是的,如果同一日期有多个个人id,那么这只是一个决胜局。
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;