Sql 在oracle中选择前N个不带内部选择的不同行

Sql 在oracle中选择前N个不带内部选择的不同行,sql,oracle,join,distinct,Sql,Oracle,Join,Distinct,我有如下结构:Table1->Table2关系为1:m 我需要执行与下一个查询类似的查询: select Table1.id from Table1 left outer join Table2 on (Table1.id1 = Table2.id2) where Table2.name like '%a%' and rownum < 11 i、 e.我希望表1中的前10个ID满足表2中的条件。问题是我必须使用distinct,但distinct子句在“rownum

我有如下结构:Table1->Table2关系为1:m

我需要执行与下一个查询类似的查询:

select Table1.id from Table1 left outer join Table2 on (Table1.id1 = Table2.id2) where Table2.name like '%a%' and rownum < 11
i、 e.我希望表1中的前10个ID满足表2中的条件。问题是我必须使用distinct,但distinct子句在“rownum<11”之后适用,因此结果可能是5条记录,即使它们的数量超过10条

显而易见的解决方案是使用以下各项:

select id from ( select Table1.id from Table1 left outer join Table2 on (Table1.id1 = Table2.id2) where Table2.name like '%a%' ) where rownum < 11
但我担心这种查询的性能。如果表1包含大约300k条记录,而表2包含大约700k条记录,那么这样的查询不是很慢吗


是否有其他查询,但没有内部选择?不幸的是,我想避免使用内部选择

对我来说,没有理由害怕表现。我认为这是解决你问题的最好办法。如果您不相信我,请查看查询的解释计划,您会发现它的行为并不像您想象的那么糟糕。

对我来说,没有理由担心性能。我认为这是解决你问题的最好办法。若你们不相信我,看看你们的查询的解释计划,你们会发现它并没有你们想象的那个么糟糕

不幸的是,我想避免使用内部 挑选

使用表2上的WHERE子句,可以将select筛选到内部联接ie。由于TABLE2.name为null,TABLE2.name与“%a%”类似,因此只能在联接彼此内部的情况下获得结果。此外,没有基于函数的索引的%a%将导致每次迭代时进行完整的表扫描

但是@lweller是完全正确的,要正确执行查询,您需要使用子查询。请记住,如果没有ORDER BY,您无法保证top X记录的顺序,可能总是“显示”值符合主键或诸如此类,但无法保证

WITH TABLE1 AS(SELECT 1 ID FROM DUAL 
               UNION ALL
               SELECT 2 ID FROM DUAL 
               UNION ALL
               SELECT 3 ID FROM DUAL 
               UNION ALL
               SELECT 4 ID FROM DUAL 
               UNION ALL
               SELECT 5 ID FROM DUAL) ,
     TABLE2 AS(SELECT 1 ID, 'AAA' NAME FROM DUAL
               UNION ALL
               SELECT 2 ID, 'ABB' NAME FROM DUAL
               UNION ALL
               SELECT 3 ID, 'ACC' NAME FROM DUAL
               UNION ALL
               SELECT 4 ID, 'ADD' NAME FROM DUAL
               UNION ALL
               SELECT 1 ID, 'BBB' NAME FROM DUAL
               ) ,
     sortable as( --here is the subquery
         SELECT
            Table1.ID ,
            ROW_NUMBER( ) OVER (ORDER BY Table2.NAME NULLS LAST) ROWOverName , --this wil handle the sort
            table2.name
           from
            Table1
            LEFT OUTER JOIN  --this left join it moot, pull the WHERE table2.name into the join to have it LEFT join as expected
            Table2
             on
            (
                Table1.id = Table2.id
            )
          WHERE
          Table2.NAME LIKE '%A%')
    SELECT * 
      FROM sortable
     WHERE ROWOverName <= 2; 
-您可以删除ROW_NUMBER分析函数并替换最初指定的最终查询

SELECT * 
  FROM sortable
 WHERE 
       ROWNUM <= 2
 ORDER BY sortable.NAME  --make sure to put in an order by!
 ;
不幸的是,我想避免使用内部 挑选

使用表2上的WHERE子句,可以将select筛选到内部联接ie。由于TABLE2.name为null,TABLE2.name与“%a%”类似,因此只能在联接彼此内部的情况下获得结果。此外,没有基于函数的索引的%a%将导致每次迭代时进行完整的表扫描

但是@lweller是完全正确的,要正确执行查询,您需要使用子查询。请记住,如果没有ORDER BY,您无法保证top X记录的顺序,可能总是“显示”值符合主键或诸如此类,但无法保证

WITH TABLE1 AS(SELECT 1 ID FROM DUAL 
               UNION ALL
               SELECT 2 ID FROM DUAL 
               UNION ALL
               SELECT 3 ID FROM DUAL 
               UNION ALL
               SELECT 4 ID FROM DUAL 
               UNION ALL
               SELECT 5 ID FROM DUAL) ,
     TABLE2 AS(SELECT 1 ID, 'AAA' NAME FROM DUAL
               UNION ALL
               SELECT 2 ID, 'ABB' NAME FROM DUAL
               UNION ALL
               SELECT 3 ID, 'ACC' NAME FROM DUAL
               UNION ALL
               SELECT 4 ID, 'ADD' NAME FROM DUAL
               UNION ALL
               SELECT 1 ID, 'BBB' NAME FROM DUAL
               ) ,
     sortable as( --here is the subquery
         SELECT
            Table1.ID ,
            ROW_NUMBER( ) OVER (ORDER BY Table2.NAME NULLS LAST) ROWOverName , --this wil handle the sort
            table2.name
           from
            Table1
            LEFT OUTER JOIN  --this left join it moot, pull the WHERE table2.name into the join to have it LEFT join as expected
            Table2
             on
            (
                Table1.id = Table2.id
            )
          WHERE
          Table2.NAME LIKE '%A%')
    SELECT * 
      FROM sortable
     WHERE ROWOverName <= 2; 
-您可以删除ROW_NUMBER分析函数并替换最初指定的最终查询

SELECT * 
  FROM sortable
 WHERE 
       ROWNUM <= 2
 ORDER BY sortable.NAME  --make sure to put in an order by!
 ;
这里根本不需要使用DISTINCT,子查询本身也没有什么不好的地方

SELECT  id
FROM    Table1
WHERE   id IN
        (
        SELECT  id
        FROM    Table2
        WHERE   name LIKE '%a%'
        )
        AND rownum < 11
请注意,订单不受保证。要保证顺序,必须使用嵌套查询:

SELECT  id
FROM    (
        SELECT  id
        FROM    Table1
        WHERE   id IN
                (
                SELECT  id
                FROM    Table2
                WHERE   name LIKE '%a%'
                )
        ORDER BY
                id -- or whatever else
        )
WHERE   rownum < 11
如果没有嵌套查询或CTE,就没有办法做到这一点。

这里根本不需要DISTINCT,子查询本身也没有什么不好的

SELECT  id
FROM    Table1
WHERE   id IN
        (
        SELECT  id
        FROM    Table2
        WHERE   name LIKE '%a%'
        )
        AND rownum < 11
请注意,订单不受保证。要保证顺序,必须使用嵌套查询:

SELECT  id
FROM    (
        SELECT  id
        FROM    Table1
        WHERE   id IN
                (
                SELECT  id
                FROM    Table2
                WHERE   name LIKE '%a%'
                )
        ORDER BY
                id -- or whatever else
        )
WHERE   rownum < 11

如果没有嵌套查询或CTE,就没有办法做到这一点。

这样的查询不是很慢吗?如果我知道真正的慢有多慢,我就能回答这个问题。这样的查询不是很慢吗?如果我知道到底有多慢,我就能回答这个问题。