2013-02-21 21 views
0

我想知道如何在不必写出(或使数据库进程)这个查询的主要部分两次的情况下执行此操作。使用相同的数据更高效地创建Oracle UNION查询

我的情况是我在查询Oracle企业数据库(我受DBA限制,所以有些解决方案可能无法正常工作,但我不确定我在什么程度上受到限制,直到我尝试并且不知道该去哪里)。

目前,我的查询如下所示:

SELECT 
     a.Field1, 
     a.Field2, 
     b.Field3, 
     b.Field4, 
     c.Field5 
    FROM 
     a, 
     b, 
     c, 
    WHERE 
      a.FieldX = b.FieldX 
     AND 
      b.FieldY = c.FieldY 

UNION 
    (
    SELECT 
     d.Field6 as Field1, 
     d.Field7 + d.Field8 as Field2, 
     MainQuery.Field3, 
     MainQuery.Field4, 
     MainQuery.Field5 
    FROM 
     (
      SELECT 
       a.Field1, 
       a.Field2, 
       b.Field3, 
       b.Field4, 
       c.Field5 
      FROM 
       a, 
       b, 
       c, 
      WHERE 
        a.FieldX = b.FieldX 
       AND 
        b.FieldY = c.FieldY 
       AND 
        a.FieldZ = 'XXXX' 
     ) MainQuery, 

     d 
    WHERE 
     MainQuery.Field1 = d.Field6 
) 

简单地说,我有一个主查询(第一部分),返回我的结果的大部分,然后我重复与主查询额外限制(a.FieldZ = 'XXXX'),并从此查询中提取数据,并使用UNION将第二个表格附加到主查询中。

我面临的主要挑战是Field1 & Field2的定义在2个查询之间发生了变化,所以我无法弄清楚如何进行简单的连接。但是我相信必须有一种方法可以实现这一点,而不必让数据库查询两次相同的数据。

有关如何使此查询更高效的任何想法?

谢谢!


基于注释,解释多一点关于这个查询 - 我所试图做的就是我的整个数据unvierse查询上半年,然后在第二个上多余的行追加查询的记录的一半,其中a.FieldZ = 'XXXX'其中计算是Field1Field2

+0

请问您可以发表表格定义吗? – twoleggedhorse 2013-02-21 14:52:05

+0

你能用这个查询解释你在现实世界中想要做什么吗? – 2013-02-21 14:53:13

+0

首先,你的伪查询是错误的(选择field6,而你只在子查询中选择5)。接下来,如果我理解正确,您希望FieldA具有不同的值,具体取决于FieldZ是否为XXX。有更好的解决方案可以做到这一点(例如'DECODE') – Najzero 2013-02-21 14:54:26

回答

2

所以,下面您的意见,您的要求似乎是“第2列是从表M服用。Additionaly,当M.fieldZ = 'XXX'一个额外的行同场从表需要D需要添加。”

在这种情况下,您将不得不使用UNION ALL或通过连接到2行表来复制记录。您可以使用WITH子句在SELECT中重用子查询。这会使其更具可读性,并且优化器可能决定只运行一次查询(通过将子查询的结果保存在temp中)。

WITH mainquery AS (SELECT /* your main query */) 
SELECT * 
    FROM mainquery 
UNION ALL 
SELECT field1, d.field2 /*, ... */ 
    FROM (SELECT * FROM mainquery WHERE fieldZ = 'XXX') m 
    JOIN d ON m.field1 = d.field6 
+0

谢谢,但我认为这是我提到保罗的同样的问题 - 因为我需要数据两种方式时FieldZ ='XXXX',这并不给我因为Case语句只会给我查询结果的后半部分。没有? – 2013-02-21 15:20:38

+0

你说得对,如果fieldZ ='XXX'',我的查询不会返回两条记录。我认为你将不得不使用UNION(你可能想要使用UNION ALL),或者通过连接到2行表(这可能导致相同的计划)来重复行。看到我更新的答案。 – 2013-02-21 15:56:01

0

略有不同使用case声明(http://www.techonthenet.com/oracle/functions/case.php

select case when FieldZ = 'XXXX' then Field6 else Field1 end as Field1, 
     case when FieldZ = 'XXXX' then Field7 + Field8 else Field2 as Field2, 
     Field3, 
     Field4, 
     Field5 
from a join b on a.FieldX = b.FieldX 
     join c on b.FieldY = c.FieldY 
     left join d on a.Field1 = d.Field6 
+0

谢谢你的代码,但是这并不能真正解决问题,因为我需要数据**两种方式,当'FieldZ ='XXXX''where case'声明只会给我的后半部分查询的结果。没有?? – 2013-02-21 15:03:52

+0

是的。数据在哪里?申请,报告或其他地方? – paul 2013-02-21 15:17:52

+0

一份报告 - 基本上加载到一张Excel表格 – 2013-02-21 15:18:52

0

如果你的目的是复制的XXXX的记录,那么你就可以简化查询到合适的加盟与case语句:

SELECT (case when a.FieldZ = 'XXXX' then a.Field1 else d.Field6 end) as Field1, 
     (case when a.FieldZ = 'XXXX' then a.Field2 else d.Field7 + d.Field8 end) as Field2, 
     b.Field3, 
     b.Field4, 
     c.Field5 
FROM a join 
    b 
    on a.FieldX = b.FieldX join 
    C 
    on b.FieldY = c.FieldY left outer join 
    d 
    on A.Field1 = d.Field6 and 
     a.FieldZ = 'XXXX' 

如果要复制这些记录,然后一些似乎是必要的union all

1

以下是我相信给你所需答案的方法。如果没有大量数据,我无法判断它是否会更快。在这里,您将扫描临时表几次,但如果基本查询从表a,b,c和d返回一小部分数据,则这可能会少一些工作。

with foo as 
    (SELECT 
     a.Field1, 
     a.Field2, 
     a.FieldZ, 
     b.Field3, 
     b.Field4, 
     c.Field5 
    FROM 
     a, 
     b, 
     c 
    WHERE 
      a.FieldX = b.FieldX 
     AND 
      b.FieldY = c.FieldY 
) 
select Field1 
     ,field2 
     ,field3 
     ,field4 
     ,field5 
from foo 
union 
select 
d.Field6 as Field1 
,d.Field7 ||'+'|| d.Field8 as Field2 
,foo.Field3 
,foo.Field4 
,foo.Field5 
from foo 
join d on foo.field1 = d.field6 
where foo.fieldz = 'XXXX' 
+0

谢谢@ jwhite9 - 这就是我最终这样做的方式。接受文森特的答复,因为他更早发布了答案。谢谢你和你的帮助! – 2013-02-21 18:47:40