如何获取联接以填写缺失值?

时间:2013-11-22 18:44:02

标签: sql oracle oracle11g

鉴于下表:

name             date           val1         val2       val3
--------------------------------------------------------------
A                11/20/2013      34           12         123
B                11/20/2013      657          3465       568 
A                11/21/2013      12           67         458
B                11/21/2013      524          45         3654  
C                11/21/2013      56           25         55432

我怎样才能得到这样的结果?

A                11/20/2013      34           12         123
B                11/20/2013      657          3465       568
C                11/20/2013      0            0          0 
A                11/21/2013      12           67         458
B                11/21/2013      524          45         3654 
C                11/21/2013      56           25         55432

我很确定这可以做到,但是无法理解。

2 个答案:

答案 0 :(得分:3)

为了包含没有条目的namesdates,您需要先生成不同名称和日期的列表。

我会使用类似于以下内容的CROSS JOIN获取列表:

select distinct t.name, c.date
from yourtable t
cross join
(
  select date
  from yourtable
) c

SQL Fiddle with Demo。获得所有名称和日期的列表后,您可以使用LEFT JOIN返回到表中以获取完整列表,包括那些零值的列表。

with cte as
(
  select distinct t.name, c.date
  from yourtable t
  cross join
  (
    select date
    from yourtable
  ) c
)
select d.name,
  d.date,
  coalesce(t.val1, 0) val1,
  coalesce(t.val2, 0) val2,
  coalesce(t.val3, 0) val3  
from cte d
left join yourtable t
  on d.name = t.name
  and d.date = t.date
order by d.date, d.name

SQL Fiddle with Demo。这将得到一个结果:

| NAME |                            DATE | VAL1 | VAL2 |  VAL3 |
|------|---------------------------------|------|------|-------|
|    A | November, 20 2013 00:00:00+0000 |   34 |   12 |   123 |
|    B | November, 20 2013 00:00:00+0000 |  657 | 3465 |   568 |
|    C | November, 20 2013 00:00:00+0000 |    0 |    0 |     0 |
|    A | November, 21 2013 00:00:00+0000 |   12 |   67 |   458 |
|    B | November, 21 2013 00:00:00+0000 |  524 |   45 |  3654 |
|    C | November, 21 2013 00:00:00+0000 |   56 |   25 | 55432 |

答案 1 :(得分:1)

另一种稍短,稍微快一点的方法,用于产生你所追求的输出,将使用partition outer join(10g以后):

with t2 as(
  select distinct name1
    from t1
)
select t2.name1
     , t1.date1
     , nvl(t1.val1, 0) as val1
     , nvl(t1.val2, 0) as val2
     , nvl(t1.val3, 0) as val3
  from t1 
  partition by (t1.date1)
  right join t2
     on (t1.name1 = t2.name1)

结果:

NAME1 DATE1            VAL1       VAL2       VAL3
----- ---------- ---------- ---------- ----------
A     11/20/2013         34         12        123 
B     11/20/2013        657       3465        568 
C     11/20/2013          0          0          0 
A     11/21/2013         12         67        458 
B     11/21/2013        524         45       3654 
C     11/21/2013         56         25      55432 

SQLFiddle Demo