2009-08-05 84 views
1

这里是代码,以帮助你理解我的问题:如何避免重复冗长的相关子查询?

create table con (content_id number); 
create table mat (material_id number, content_id number, resolution number, file_location varchar2(50), file_size number); 
create table con_groups (content_group_id number, content_id number); 

insert into con values (99); 
insert into mat values (1, 99, 7, 'C:\foo.jpg', 1024); 
insert into mat values (2, 99, 2, '\\server\xyz.mov', 350000); 
insert into mat values (3, 99, 5, '\\server2\xyz.wav', 175000); 
insert into con values (100); 
insert into mat values (4, 100, 5, 'C:\bar.png', 2048); 
insert into mat values (5, 100, 3, '\\server\xyz.mov', 27400); 
insert into mat values (6, 100, 7, '\\server2\xyz.wav', 400); 

insert into con_groups values (10, 99); 
insert into con_groups values (10, 100); 

SELECT m.material_id, 
     m.content_id, 
     (SELECT max(file_location) keep (dense_rank first order by resolution desc)     
      FROM mat 
     WHERE mat.content_id = m.content_id 
     /* AND ... 
      AND ... 
      AND ... */) special_mat_file_location, 
     (SELECT max(file_size) keep (dense_rank first order by resolution desc) 
      FROM mat 
     WHERE mat.content_id = m.content_id 
     /* AND ... 
      AND ... 
      AND ... */) special_mat_file_size 
    FROM mat m 
WHERE m.material_id IN (select material_id 
          from mat 
        inner join con on con.content_id = mat.content_id 
        inner join con_groups on con_groups.content_id = con.content_id 
          where con_groups.content_group_id = 10); 

我把评论与门来强调,这是一个简单的例子;在我真正的查询中的子查询更复杂,更多的标准。

我的问题是:我想避免在两个列(file_location and file_size)的子查询中重复所有条件,因为条件完全相同。我很乐意使用公用表表达式(即使用WITH子句进行子查询分解),但是我不能因为子查询中的“WHERE mat.content_id = m.content_id”,而使它成为相关的子查询。我的理解是,不能使用WITH子句对相关子查询进行因子分解。出于同样的原因,我也不能把这个子查询作为内联视图(又名派生表)放在FROM子句中。

如何包含一次标准并将相关子查询添加到结果集中?

+0

它只是简单地查询您担心的文本大小或查询性能? – jva 2009-08-05 19:42:28

+0

这是一个很好的问题。如果子查询的标准发生变化(这是一种真正的可能性),我很担心以后再维护这个查询。所以,是的,我担心查询文本的大小。 – 2009-08-05 20:19:31

回答

1

使用子查询因子分析(这是Oracle称之为 - 它在SQL Server中称为公用表表达式)。支持9i +:

WITH file AS (
    SELECT t.content_id, 
     MAX(t.file_location) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileLocation', 
     MAX(t.file_size) keep (DENSE_RANK t.first ORDER BY t.resolution DESC) 'fileSize' 
    FROM mat t 
GROUP BY t.content_id) 
SELECT m.material_id, 
     m.content_id, 
     f.fileLocation, 
     f.fileSize 
    FROM mat m 
    JOIN file f ON f.content_id = m.content_id 

它旨在用于内联视图重用。您概括该视图,并为JOIN子句中的不同实例定义特定的筛选。您需要公开列以加入SELECT子句 - 请参阅content_id作为示例。

相关的子查询意味着它可以重写为JOIN - 相关性是JOIN标准。

您可以在子查询分解中定义多个视图 - 如果您提供了更多细节,我可以更好地定制答案。

+0

任何人都可以解释为什么这是更好的简单的加入FROM子句?或者甚至将子查询逻辑放在单独的视图中? – jva 2009-08-05 19:56:25

+0

回复:“相关的子查询意味着它可以重写为JOIN” - 这是一个有趣的想法。虽然我的查询有点麻烦。它说文件是一个无效的表名,所以我重命名了它。然后它不喜欢如何命名聚合列,所以我改变了它。现在,我收到content_id的消息“ORA-00937:不是单组功能”。我完全误解了什么吗? – 2009-08-05 20:07:36

+0

@jva:谷歌“子查询保理”。 – 2009-08-05 20:47:27

0

我想我明白了。我能只抓“特殊”材料的主键,而在另一个层包住主查询,像这样:

  SELECT x.material_id, 
       x.content_id, 
       sp_m.file_location, 
       sp_m.file_size 
      FROM (SELECT m.material_id, 
         m.content_id, 
         (SELECT max(material_id) keep (dense_rank first order by resolution desc)     
          FROM mat 
          WHERE mat.content_id = m.content_id 
         /* AND ... 
          AND ... 
          AND ... */) special_mat_primary_key 
        FROM mat m 
        WHERE m.material_id IN (select material_id 
              from mat 
             inner join con on con.content_id = mat.content_id 
             inner join con_groups on con_groups.content_id = con.content_id 
              where con_groups.content_group_id = 10)) x 
LEFT OUTER JOIN mat sp_m ON sp_m.material_id = x.special_mat_primary_key; 

让我知道你在想什么。

+0

相关的子选择表示它将针对返回的每一行执行。 IN子句是查询事物的下一个性能最差的方法。您正在创建一个内联视图,其中包含的信息比您需要的更多。 – 2009-08-05 21:23:25