1

我有两个查询,如下所示。查询选择相同的表,但具有不同的条件和列数。我无法解决如何组合这些;有什么办法吗?

第一个查询是:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 1, 1, 0)) filled
  FROM tableA a,
       tableB b
 WHERE a.branchCode = b.branchCode
   AND a.registerNumber IN (SELECT c.registerNumber
                              FROM tableC c
                             WHERE c.registerDate <= '01.02.2013'
                               AND c.state = 'A'
                               AND c.contractState != 2)
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type;

结果如下所示:

BranchNumber     CountryCode    Type Filled
1452                 USA          0    5
1452                 USA          2    8
1452                 USA          1    16
7854                 GER          0    10
7854                 GER          1    3

第二个查询是:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 0, 1, 0)) free, 
       SUM(DECODE(a.status, 2, 1, 0)) damaged    
  FROM tableA a,
       tableB b  
 WHERE a.kks_kayitdrm = 'A'    
   AND a.branchCode = b.branchCode    
   AND a.recordDate <= '01.02.2013'  
 GROUP BY b.centerBranchNumber,
           a.type,
           b.countryCode;

结果是:

BranchNumber     CountryCode    Type Free     Damage
1452                 USA          0    5        2  
1452                 USA          2    8        1  
1452                 USA          1    16       5
7854                 GER          0    10       9  
7854                 GER          1    3        16

如果我结合起来,我希望得到如下结果:

BranchNumber     CountryCode    Type   Filled    Free     Damage
1452                 USA          0      1         5        2  
1452                 USA          2      2         8        1  
1452                 USA          1      65        16       5
7854                 GER          0      7         10       9  
7854                 GER          1      45        3        16   
4

1 回答 1

1

您的第一个查询可以重写如下:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 1, 1, 0)) filled
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE c.registerDate <= '01.02.2013'
   AND c.state = 'A'
   AND c.contractState != 2
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

将您的第二个语法也转换为 ANSI 语法(这将有助于更复杂的查询,因为当您做错了什么时非常明显)它变成了这样:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type,
       SUM(DECODE(a.status, 0, 1, 0)) free, 
       SUM(DECODE(a.status, 2, 1, 0)) damaged    
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode      
 WHERE a.kks_kayitdrm = 'A'
   AND a.recordDate <= '01.02.2013'  
 GROUP BY b.centerBranchNumber,
           a.type,
           b.countryCode

如您所见,两个查询之间存在大量相似性。为了得到你想要的结果集,有两种方法。将不相似的条件移动到 SUM 中的 CASE 语句中。或者,您可以将所有两个查询联合在一起并再次求和。我更喜欢使用 CASE 语句,因为您可以减少必须做的工作量;缺点是查询变得不太容易阅读。

您查询的常见部分是:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode 
 GROUP BY b.centerBranchNumber,
          a.type,
          b.countryCode

以此为基础,您可以慢慢添加,直到获得相同的结果。您必须记住将相同的条件添加到 WHERE / JOINS 以确保获得相同的结果。

如果我们首先添加您的所有条件;您必须将第一个查询中 tableC 上的 JOIN 更改为 LEFT OUTER JOIN。这与 WHERE 子句将结果集限制为 INNER JOIN 完全相同。

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE c.registerDate <= '01.02.2013'
   AND c.state = 'A'
   AND c.contractState != 2
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

在第二个查询中添加条件,您现在需要在 WHERE 子句中使用 OR:

SELECT b.centerBranchNumber,
       b.countryCode,
       a.type
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE ( c.registerDate <= '01.02.2013'
         AND c.state = 'A'
         AND c.contractState != 2 
             )
    OR ( a.kks_kayitdrm = 'A'
         AND a.recordDate <= '01.02.2013' 
             )
 GROUP BY b.centerBranchNumber,
          b.countryCode,
          a.type

接下来,你的约会似乎有点奇怪。您似乎没有将字符串文字转换为'01.02.2013'日期,并且由于它不是 YYYYMMDD 的形式,因此您的比较将不起作用。您依赖于您的NLS_DATE_FORMAT是 form DD.MM.YYYY,您不能保证每个会话都如此。要比较日期,您应该使用内置TO_DATE()函数和适当的格式模型或 ANSI日期时间文字显式转换,正如我在此答案中更全面地解释的那样。

只需说 Oracle明确建议不要使用隐式转换,因为:

  • 使用显式数据类型转换函数时,SQL 语句更容易理解。

  • 隐式数据类型转换会对性能产生负面影响,尤其是在将列值的数据类型转换为常量而不是相反时。

  • 隐式转换取决于它发生的上下文,并且可能不会在每种情况下都以相同的方式工作。例如,从日期时间值到 VARCHAR2 值的隐式转换可能会返回意外年份,具体取决于 NLS_DATE_FORMAT 参数的值。

  • 隐式转换的算法可能会随着软件版本和 Oracle 产品的变化而变化。显式转换的行为更可预测。

因此,为了比较您的日期,我建议使用 TO_DATE(),例如:

WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')

最后,我们可以添加 SUM;这意味着在其中重复您以前的条件。您可以为您的第一个查询简化这一点,因为某物是否“填充”完全取决于 LEFT OUTER JOIN,这意味着如果该registerNumber表在 JOIN 中不为空,则条件为真。

在这两种情况下,我都使用 CASE 语句而不是 DECODE;这是因为 CASE 更强大,并且强制执行正确的数据类型,而 DECODE 无法保证这一点

将所有这些放在一起,您的最终查询将变为:

SELECT b.centerBranchNumber
     , b.countryCode
     , a.type
     , sum(case when a.status = 1 and c.registernumber is not null then 1
                else 0
           end) as filled
     , sum(case when a.status = 0 
                     and a.kks_kayitdrm = 'A'
                     and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
                     then 1
                else 0
           end) as free
     , sum(case when a.status = 2
                     and a.kks_kayitdrm = 'A'
                     and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
                     then 1
                else 0
           end) as damaged
  FROM tableA a
  JOIN tableB b
    ON a.branchCode = b.branchCode
  LEFT OUTER JOIN tableC 
    ON a.registerNumber = c.registerNumber
 WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')
         AND c.state = 'A'
         AND c.contractState != 2 
             )
    OR ( a.kks_kayitdrm = 'A'
         AND a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
             )
 GROUP BY b.centerBranchNumber
        , b.countryCode
        , a.type

您可以更通用地使用此方法在适当的地方组合查询。

于 2013-02-05T08:44:38.633 回答