返回没有NOT EXISTS的默认行

时间:2015-10-19 09:13:10

标签: sql oracle

我有一个返回单行的查询

SELECT
  'abcde' type,
  NVL(SUM(something),0) value
FROM
  tableA a,
  tableB b
WHERE
  a.id=b.id;

在这种情况下,如果条件满足,则返回以下内容,

TYPE   VALUE
-------------
abcde   100

如果条件不满足,它将不会返回任何行。在这种情况下我需要返回一个默认行,例如,

TYPE   VALUE
-------------
abcde   0

我尝试使用WHERE NOT EXISTS,但在这种情况下,我必须在WHERE NOT EXISTS(my_large_query)中包含大型查询。

SELECT
  'abcde' type,
  NVL(SUM(something),0) value
FROM
  tableA a,
  tableB b
WHERE
  a.id=b.id
GROUP BY
  'abcde'
UNION
SELECT
  'abcde' type,
  0 value
FROM
  dual
WHERE
  NOT EXISTS
  (
    SELECT
      'abcde' type,
      NVL(SUM(something),0) value
    FROM
      tableA a,
      tableB b
    WHERE
      a.id=b.id
  );

我可以使用其他任何方式吗?如果我使用NOT EXISTS

,则会出现任何性能问题

4 个答案:

答案 0 :(得分:1)

你想用'abcde'选择一个记录,所以从dual中选择它。你得到子查询中的总和。

select 
  'abcde' type,
  nvl(
  (
    SELECT SUM(something)
    FROM tableA a
    JOIN tableB ON a.id=b.id
  ), 0) as value
from dual;

更新:如果你想从表中获得更多的聚合,你可以用三个子查询来做这个,但是对同一个查询进行三次查询是无效的。所以你可以使用外连接。因为你的表的聚合与双表完全无关,但是,这看起来有点奇怪,但是,查询奇怪的,包括外部交叉连接: - )

select 
  'abcde' as type, 
  nvl(sum_current, 0) as sum_curr,
  nvl(sum_previous, 0) as sum_prev
from dual
left join
(
  select 
    sum(data_current) as sum_current,
    sum(data_prev) as sum_previous
  from tablea a
  join tableb on a.id = b.id
) on 1 = 1; -- cross-outer joining

如果没有1 = 1虚拟ON子句,这里也是一样的。我们选择类型'abcde'以及聚合,并将其用于连接。

select 
  'abcde' as type, 
  nvl(sum_current, 0) as sum_curr,
  nvl(sum_previous, 0) as sum_prev
from (select 'abcde' as type from dual)
left join
(
  select 
    'abcde' as type,
    sum(data_current) as sum_current,
    avg(data_prev) as sum_previous
  from tablea a
  join tableb on a.id = b.id
) using (type);

选择您最喜欢的查询。

答案 1 :(得分:0)

如果我理解了问题,你需要使用FULL OUTER JOIN

SELECT
  'abcde' type,
  NVL(SUM(something),0) value
FROM tableA a
FULL OUTER JOIN tableB b ON a.id=b.id
GROUP BY 'abcde'

答案 2 :(得分:0)

您可以使用 [LEFT | RIGHT] OUTER JOIN

例如,在SCOTT模式中使用标准EMP和DEPT表:

lmfit  <- speedlm(formula , res, fitted=TRUE)
resids <- res$Daily_gain - predict(lmfit, newdata=res)
print(summary(resids))

# Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's
#   NA      NA      NA     NaN      NA      NA  829780

在上面的输出中,您可以看到使用 RIGHT OUTER JOIN DEPT = 40 还有一行。

尝试此查询:

SQL> SELECT d.deptno,
  2    NVL(e.empno, 0) empno
  3  FROM emp e
  4  RIGHT OUTER JOIN dept d
  5  ON e.deptno       = d.deptno
  6  AND d.deptno     IN (30,40);

    DEPTNO      EMPNO
---------- ----------
        10          0
        20          0
        30       7499
        30       7521
        30       7654
        30       7698
        30       7844
        30       7900
        40          0

9 rows selected.

答案 3 :(得分:0)

Eeepi,嗨!

  

在我看来,我们这里有一个XY问题。你可以尝试解决这个问题   使用PL / SQL,因为您已将问题标记为Oracle相关。

但是,严格回答你的问题:1。是的,我们可以使用纯SQL解决你的问题; 2.是的,使用not exists的查询会获得一些性能损失,因为没有任何免费的。

我们需要考虑在这种情况下对绩效的影响是微不足道的。 例如,使用UNION关键字(在您的示例中)将要贵1000倍 - 因此,如果您不希望Oracle引擎排序并比较所有行,请始终使用UNION ALL在查询中。

您需要的查询是:

WITH
 t AS
 (SELECT 'abcde' TYPE
        ,nvl(SUM(something), 0) VALUE
    FROM tableA a
        ,tableB b
   WHERE a.id = b.id)
SELECT *
  FROM (
        SELECT *
          FROM t

        UNION ALL

        SELECT 'abcde',  0 
          FROM dual
         WHERE NOT EXISTS (SELECT * FROM t)
       )