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' 的不同值,同时忽略其他值(假设这确实是要求),并分别计算每个 id
的 total
列中的总数 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)
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' 的不同值,同时忽略其他值(假设这确实是要求),并分别计算每个 id
的 total
列中的总数 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)