这是我开始的配置:
DROP TABLE ruleset1;
CREATE TABLE ruleset1 (id int not null unique,score_rule1 float default 0.0,score_rule2 float default 0.0,score_rule3 float default 0.0);
DROP TABLE ruleset2;
CREATE TABLE ruleset2 (id int not null unique,score_rule1 float default 0.0,score_rule2 float default 0.0,score_rule3 float default 0.0);
insert into ruleset1 (id, score_rule1, score_rule2, score_rule3) values (0,0.8,0,0);
insert into ruleset1 (id, score_rule1, score_rule2, score_rule3) values (1,0,0.1,0);
insert into ruleset2 (id, score_rule1, score_rule2, score_rule3) values (0,0,0,0.3);
insert into ruleset2 (id, score_rule1, score_rule2, score_rule3) values (2,0,0.2,0);
我现在拥有的是2张桌子 ruleset1:
| ID | SCORE_RULE1 | SCORE_RULE2 | SCORE_RULE3
================================================
| 0 | 0.8 | 0 | 0
| 1 | 0 | 0.1 | 0
和ruleset2:
| ID | SCORE_RULE1 | SCORE_RULE2 | SCORE_RULE3
================================================
| 0 | 0 | 0 | 0.3
| 2 | 0 | 0.2 | 0
我希望外连接它们并计算非零列的平均值,如下所示:
| ID | Average
================
| 0 | 0.55
| 1 | 0.1
| 2 | 0.2
我目前的查询是:
select * from ruleset1 full outer join ruleset2 on ruleset1.id = ruleset2.id;
给出了一个丑陋的结果:
| ID | SCORE_RULE1 | SCORE_RULE2 | SCORE_RULE3 | ID | SCORE_RULE1 | SCORE_RULE2 | SCORE_RULE3
============================================================================================
| 0 | .8 | 0 | 0 | 0 | 0 | 0 | .3
| - | - | - | - | 2 | 0 | .2 | 0
| 1 | 0 | .1 | 0 | - | - | - | -
有人可以提供更好的查询吗? 非常感谢你!
答案 0 :(得分:3)
当然avg
不会忽略零,只会忽略NULL,因此可以使用NULLIF(column, 0)
。
但是,当你得到非规范化数据时,你可以简单地将其正常化:
select id, avg(score)
from
(
select id, score_rule1 score
from ruleset1 where score_rule1 <> 0
union all
select id, score_rule2 from ruleset1 where score_rule2 <> 0
union all
select id, score_rule3 from ruleset1 where score_rule3 <> 0
union all
select id, score_rule1 from ruleset2 where score_rule1 <> 0
union all
select id, score_rule2 from ruleset2 where score_rule2 <> 0
union all
select id, score_rule3 from ruleset2 where score_rule3 <> 0
) dt
group by id;
为了避免五个联盟,你只能使用一个并做一些额外的逻辑:
select id, sum(score) / sum(score_count)
from
(
select id, score_rule1 + score_rule2 + score_rule3 score,
case when score_rule1 = 0 then 0 else 1 end +
case when score_rule2 = 0 then 0 else 1 end +
case when score_rule3 = 0 then 0 else 1 end score_count
from ruleset1
union all
select id, score_rule1 + score_rule2 + score_rule3 score,
case when score_rule1 = 0 then 0 else 1 end +
case when score_rule2 = 0 then 0 else 1 end +
case when score_rule3 = 0 then 0 else 1 end score_count
from ruleset2
) dt
group by id;
这假设core_rule列中没有NULL。
答案 1 :(得分:0)
这是PostgreSQL的一个例子,你可以适应Oracle(抱歉,SQLFiddle的甲骨文没有合作)。感谢Juan Carlos Oropeza的建议,下面的代码很好地运行在Oracle上:http://rextester.com/DVP59353
select
r.id,
sum(coalesce(r1.score_rule1,0) +
coalesce(r1.score_rule2,0) +
coalesce(r1.score_rule3,0) +
coalesce(r2.score_rule1,0) +
coalesce(r2.score_rule2,0) +
coalesce(r2.score_rule3,0)
)
/
sum(case when coalesce(r1.score_rule1,0) <> 0 then 1 else 0 end +
case when coalesce(r1.score_rule2,0) <> 0 then 1 else 0 end +
case when coalesce(r1.score_rule3,0) <> 0 then 1 else 0 end +
case when coalesce(r2.score_rule1,0) <> 0 then 1 else 0 end +
case when coalesce(r2.score_rule2,0) <> 0 then 1 else 0 end +
case when coalesce(r2.score_rule3,0) <> 0 then 1 else 0 end) as Average
from
(select id from ruleset1
union
select id from ruleset2) r
left join ruleset1 r1 on r.id = r1.id
left join ruleset2 r2 on r.id = r2.id
group by r.id
PostFSQL版本的SQLFiddle在这里:http://sqlfiddle.com/#!15/24e3f/1。
此示例使用union
组合来自两个表的id。这样做允许ruleset1和ruleset2中的相同ID在结果中只出现一次。 r
是为此生成的表提供的别名。
然后将所有id
与两个表连接起来。在求和过程中,左连接产生的NULL值可能会影响结果。因此,NULL在数学中合并为零。
答案 2 :(得分:0)
dnoeth是一个简单而干净的答案。
这里我只是在玩COALESCE
和NVL2
select COALESCE(r.ID, s.ID),
COALESCE(r.score_rule1, 0) +
COALESCE(r.score_rule2, 0) +
COALESCE(r.score_rule3, 0) +
COALESCE(s.score_rule1, 0) +
COALESCE(s.score_rule2, 0) +
COALESCE(s.score_rule3, 0) as sum,
NVL2(r.score_rule1, 0, 1) +
NVL2(r.score_rule2, 0, 1) +
NVL2(r.score_rule3, 0, 1) +
NVL2(s.score_rule1, 0, 1) +
NVL2(s.score_rule2, 0, 1) +
NVL2(s.score_rule3, 0, 1) as tot
from ruleset1 r
full outer join ruleset2 s
on ruleset1.id = ruleset2.id;
然后您的平均值为sum/tot
答案 3 :(得分:0)
union all
您的两个表,取消忽略,使用nullif
将零更改为null,并使用标准avg()
聚合函数:
select id, avg(nullif(value, 0)) as avg_value from (
select * from ruleset1
union all
select * from ruleset2
)
unpivot ( value for column_name in (score_rule1, score_rule2, score_rule3))
group by id
order by id
;
ID AVG_VALUE
---------- ----------
0 .55
1 .1
2 .2
答案 4 :(得分:-1)
SELECT s.id, AVG(s.score)
FROM(
SELECT id,score_rule1+score_rule2+score_rule3 as score
FROM ruleset2
UNION ALL
SELECT id,(score_rule1+score_rule2+score_rule3) as score
FROM ruleset1) s
group by s.id