SQL Query加入内部选择

时间:2011-01-25 00:12:52

标签: sql oracle

我可能以错误的方式做到这一点......但这就是我所拥有的......这是一个带有数据模型的Oracle实例:

TABLE 1
-----------
ID | NAME |
-----------

TABLE 2
----------------------------------------------
ID | NAME | TABLE_1_ID | TIMESTAMP | SOME_NUM
----------------------------------------------

TABLE 3
-----------------------
ID | NAME | TABLE_1_ID
-----------------------

我想要一个给我4列的查询:

  • t1.name
  • 表2中所有条目的计数,其中SOME_NUM = 1且t1.id = t2.table_1_id
  • 表2中所有条目的计数,其中TIMESTAMP在两个值之间且t1.id = t2.table_1_id
  • 表3中所有条目的计数,其中t1.id = t3.table_1_id

我希望表1与其他两个表相比较小。

以下是我为生成前两组所做的工作:

select t1.name, a.count
from 
   ( select TABLE_1_ID, COUNT(*) count
     from TABLE_2
     group by TABLE_1_ID
   ) a,
table_1 t1
where t1.id = a.table_1_id

这很有用......但是当我试图获得第三列时,这就失败了。

select t1.name, a.count, b.count2
from 
   ( select TABLE_1_ID, COUNT(*) count
     from TABLE_2
     group by TABLE_1_ID
   ) a,
   ( select TABLE_1_ID, COUNT(*) count2
     from TABLE_2
     where TIMESTAMP < ? and TIMESTAMP > ?
     group by TABLE_1_ID
   ) b,

table_1 t1
where t1.id = a.table_1_id and t1.id = b.table_1_id

这不会返回任何不满足有关时间戳的where子句的条目。如果我改变了和一个或者,我会重复t1.names。

我不太擅长SQL,你可以说。我认为它在这里进行内连接,但我想我想要一个外连接,因为我想要一个与TABLE_1具有相同行数的结果集。在理解如何正确获得第三个结果之前,我甚至不想尝试第四个结果。

2 个答案:

答案 0 :(得分:2)

试试这个:

   SELECT t1.NAME,  
          SUM(CASE 
                WHEN t2.some_num = 1 THEN 1 
                ELSE 0 
              END),
          SUM(CASE 
                WHEN t2.timestamp BETWEEN SYSDATE-1 AND SYSDATE+1 THEN 1 
                ELSE 0 
              END),
          t3.cnt
     FROM table1 t1 
LEFT JOIN table2 t2 ON t1.ID = t2.table_1_id 
LEFT JOIN (SELECT table_1_id, 
                  COUNT(1) cnt 
             FROM table3 
         GROUP BY table_1_id) t3 ON t1.id = t3.table_1_id
 GROUP BY t1.name

答案 1 :(得分:0)

有人建议第二种形式是可取的,但对于所有表现,这取决于你的数据 - 使用最适合你的方式

选项1:

而不是JOIN,只需将它们显示为为列提供标量值的子查询。

即。最多第3列

select
   t1.name,
   ( select COUNT(*)
     from TABLE_2 a
     WHERE a.TABLE_1_ID = t1.ID
   ) a_count,
   ( select COUNT(*)
     from TABLE_2 b
     where b.TIMESTAMP < ? and b.TIMESTAMP > ?
       AND t1.id = b.table_1_id
   ) b_count

from table_1 t1

这需要N x C子选择,t1中每行对应一列。

如果表不是太大,或者每个子查询在table_1_id上都有一个好的索引,那么合理地工作,这样子查询总访问量就不会超过全表扫描的行数。请记住,count(*)查询可以直接从索引页面满足,而无需查找实际的表数据,因此它非常快。

选项2:

对所涉及的每个表执行单次传递,并将它们连接在一起。

select t1.name, nvl(a.count1,0) count1, nvl(b.count2,0) count2
from table_1 t1
left join
   ( select TABLE_1_ID, COUNT(*) count1
     from TABLE_2
     group by TABLE_1_ID
   ) a ON t1.id = a.table_1_id
left join
   ( select TABLE_1_ID, COUNT(*) count2
     from TABLE_2
     where TIMESTAMP < ? and TIMESTAMP > ?
     group by TABLE_1_ID
   ) b ON t1.id = b.table_1_id

左连接子选择(按TABLE_1_ID分组)确保TABLE1.ID为1行,或者没有行。这可以防止笛卡尔产品的出现。现在您可以获取计数,但添加了NVL,因为在此表单中,count可能会返回为NULL。

在显示的第一种形式中,count永远不会为NULL。