在同时旋转的同时拉动数据

时间:2017-01-04 16:17:27

标签: sql oracle sybase

   ID | Type     | Code
   1    Purchase   A1
   1    Return     B1
   1    Exchange   C1
   2    Purchase   D1
   2    Return     NULL
   2    Exchange   F1
   3    Purchase   G1
   3    Return     H1
   3    Exchange   I1
   4    Purchase   J1
   4    Exchange   K1

以上是样本数据。我想要回归的是:

ID | Type     | Code
 1    Purchase   A1
 1    Return     B1
 1    Exchange   C1
 3    Purchase   G1
 3    Return     H1
 3    Exchange   I1

因此,如果某个字段在代码中为空,或者该ID不存在Purchase,Return和Exchange的值,则完全忽略该ID。然而,还有最后一步。我希望这些数据以这种方式转动:

ID | Purchase | Return | Exchange
1    A1         B1       C1
3    G1         H1       I1

我昨天问过这个没有枢轴部分,你可以在这里看到:

SQL query to return data only if ALL necessary columns are present and not NULL

但是我忘记了最后一部分。我试着玩excel但没有运气。我试图制作一个临时表但数据太大而无法做到这一点所以我想知道这是否可以在1 sql语句中完成?

我个人成功地使用了这个查询:

select t.*
from t
where 3 = (select count(distinct t2.type)
       from t t2
       where t2.id = t.id and
             t2.type in ('Purchase', 'Exchange', 'Return') and
             t2.Code is not null
      );

那么我们如何调整它以包括枢轴部分。这可能吗?

3 个答案:

答案 0 :(得分:2)

很容易。只需使用条件聚合:

select t.id,
       max(case when type = 'Purchase' then code end) as Purchase,
       max(case when type = 'Exchange' then code end) as Exchange,
       max(case when type = 'Return' then code end) as Return
from t
where 3 = (select count(distinct t2.type)
       from t t2
       where t2.id = t.id and
             t2.type in ('Purchase', 'Exchange', 'Return') and
             t2.Code is not null
      )
group by t.id;

在没有子查询的情况下使用having来表达(在我看来)实际上更简单:

select t.id,
       max(case when type = 'Purchase' then code end) as Purchase,
       max(case when type = 'Exchange' then code end) as Exchange,
       max(case when type = 'Return' then code end) as Return
from t
group by t.id
having max(case when type = 'Purchase' then code end) is not null and
       max(case when type = 'Exchange' then code end) is not null and
       max(case when type = 'Return' then code end) is not null;

许多数据库都允许:

having Purchase is not null and Exchange is not null and Return is not null

但Oracle不允许在having子句中使用表别名。

答案 1 :(得分:1)

更新 - 根据问题评论中的讨论,我之前的查询有一个错误的假设(我从我认为在问题中的原始查询中看到的那个结转);我已经消除了这个不好的假设。

select id
     , max(case when type='Purchase' then Code end) Purchase
     , max(case when type='Return' then Code end) Return
     , max(case when type='Exchange' then Code end) Exchange
  from t
 where code is not null
   and type in ('Purchase', 'Return', 'Exchange')
 group by id
having count(distinct type) = 3

答案 2 :(得分:0)

我将再次指出(正如我在你的其他线程中所做的那样)分析函数将更快地完成工作 - 它们需要只读取一次基表,并且没有显式或隐式连接。

   with
         test_data ( id, type, code ) as (
           select 1, 'Purchase', 'A1' from dual union all
           select 1, 'Return'  , 'B1' from dual union all
           select 1, 'Exchange', 'C1' from dual union all
           select 2, 'Purchase', 'D1' from dual union all
           select 2, 'Return'  , null from dual union all
           select 2, 'Exchange', 'F1' from dual union all
           select 3, 'Purchase', 'G1' from dual union all
           select 3, 'Return'  , 'H1' from dual union all
           select 3, 'Exchange', 'I1' from dual union all
           select 4, 'Purchase', 'J1' from dual union all
           select 4, 'Exchange', 'K1' from dual
         )
    -- end of test data; actual solution (SQL query) begins below this line
select id, purchase, return, exchange
from   ( select id, type, code
         from   ( select id, type, code,
                    count( distinct case when type in ('Purchase', 'Return', 'Exchange')
                                         then type end                         
                         ) over (partition by id)             as ct_type,
                    count( case when code is null then 1 end
                         ) over (partition by id)             as ct_code
                  from   test_data
                )
         where  ct_type = 3 and ct_code = 0
       )
pivot  ( min(code) for type in ('Purchase' as purchase, 'Return'   as return, 
                                                        'Exchange' as exchange)
       )
;

输出:

 ID PURCHASE RETURN   EXCHANGE
--- -------- -------- --------
  1 A1       B1       C1
  3 G1       H1       I1

2 rows selected.