SQL 查询 return 数据仅当所有必要的列都存在且不为 NULL 时

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

ID | Type     | total
1    Purchase   12
1    Return     2
1    Exchange   5
2    Purchase   null
2    Return     5
2    Exchange   1
3    Purchase   34
3    Return     4
3    Exchange   2
4    Purchase   12
4    Exchange   2

以上是示例数据。我要return的是:

ID | Type     | total
 1    Purchase   12
 1    Return     2
 1    Exchange   5
 3    Purchase   34
 3    Return     4
 3    Exchange   2

因此,如果某个字段总计为空,或者 Purchase、Return 和 Exchange 的值并非都存在于该 ID,则完全忽略该 ID。我该怎么做呢?

您可以使用 exists。我想你打算:

select t.*
from t
where exists (select 1
              from t t2
              where t2.id = t.id and t2.type = 'Purchase' and t2.total is not null
             ) and
      exists (select 1
              from t t2
              where t2.id = t.id and t2.type = 'Exchange' and t2.total is not null
             ) and
      exists (select 1
              from t t2
              where t2.id = t.id and t2.type = 'Return' and t2.total is not null
             );

有一些方法可以"simplify"这个:

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.total is not null
          );

我会把它写成一个没有子查询的连接:

SELECT pur.id, pur.total AS Purchase, exc.total AS Exchange, ret.total AS Return
FROM MyTable as pur
INNER JOIN MyTable AS exc ON exc.id=pur.id AND exc.type='Exchange'
INNER JOIN MyTable AS ret ON ret.id=pur.id AND ret.type='Return'
WHERE pur.type='Purchase'

内连接意味着如果对于给定的 id 没有找到具有不同值的三行中的任何一行,则结果中不包含任何行。

解析函数是解决此类问题的好方法。基础 table 只读取一次,不需要连接(显式或隐式,如 EXISTS 条件或相关子查询)。

在下面的解决方案中,我们为每个 id 计算 'Purchase'、'Exchange' 和 'Return' 的不同值,同时忽略其他值(假设这确实是要求),并分别计算每个 idtotal 列中的总数 null。然后,select 只是外部查询中的 "desired" 行就变得微不足道了。

    with
         test_data ( id, type, total ) as (
           select 1, 'Purchase', 12   from dual union all
           select 1, 'Return'  , 2    from dual union all
           select 1, 'Exchange', 5    from dual union all
           select 2, 'Purchase', null from dual union all
           select 2, 'Return'  , 5    from dual union all
           select 2, 'Exchange', 1    from dual union all
           select 3, 'Purchase', 34   from dual union all
           select 3, 'Return'  , 4    from dual union all
           select 3, 'Exchange', 2    from dual union all
           select 4, 'Purchase', 12   from dual union all
           select 4, 'Exchange', 2    from dual
         )
    -- end of test data; actual solution (SQL query) begins below this line
    select id, type, total
    from   ( select id, type, total,
                    count( distinct case when type in ('Purchase', 'Return', 'Exchange')
                                         then type end                         
                         ) over (partition by id)             as ct_type,
                    count( case when total is null then 1 end
                         ) over (partition by id)             as ct_total
             from   test_data
           )
    where  ct_type = 3 and ct_total = 0
    ;

输出:

    ID  TYPE      TOTAL
    --  --------  -----
     1  Exchange      5
     1  Purchase     12
     1  Return        2
     3  Exchange      2
     3  Purchase     34
     3  Return        4

即使将新值添加到 type

,这也应该可以正常工作
select * from t where 
ID not in(select ID from t where 
t.total is null or t.[Type] is null)