在oracle sql中联接2个表
以下是我开始使用的配置:在oracle sql中联接2个表,sql,oracle,join,Sql,Oracle,Join,以下是我开始使用的配置: 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
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);
我现在有两张桌子
规则集1:
| ID | SCORE_RULE1 | SCORE_RULE2 | SCORE_RULE3
================================================
| 0 | 0.8 | 0 | 0
| 1 | 0 | 0.1 | 0
和规则集2:
| 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 | - | - | - | -
有谁能帮我提出一个更好的问题吗?
多谢各位 当然,avg不会忽略零,只忽略空值,因此可以使用NULLIFcolumn,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;
这假设核心规则列中没有空值。这里有一个PostgreSQL示例,您可以使用Oracle进行调整。对不起,SQLFiddle的Oracle不配合。由于Juan Carlos Oropeza的建议,以下代码在Oracle上运行良好:
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
SQLFiddle with PostgreSQL版本在此处:
此示例使用union组合来自两个表的id。这样做允许ruleset1和ruleset2中的相同ID在结果中只出现一次。r是这个生成的表的别名
然后将所有ID与两个表保持连接。在求和过程中,左联接产生的空值可能会影响结果。因此,在数学中,空值合并为零 dnoeth是一个简单明了的答案 在这里,我只是在玩COALESCE和NVL2 然后,您的平均值为sum/tot将所有两个表合并,取消PIVOT,使用nullif将零更改为null,并使用标准平均值聚合函数:
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
那么,你不需要在某个地方使用avg函数吗?你的桌子设计看起来有缺陷。为什么您需要两张存储相同内容的桌子?在一个表中添加一个规则集列。在计算平均值时,你是否忽略了零?是的,我只是忽略了零,而对于avg函数,它似乎不起作用。你可以解释你是如何得到0.55-0.1-0.2的,你知道,对于我们这些从大学开始就不太喜欢统计的人来说:我不明白,为什么忽略0值?这不是平均值,是吗?很接近,但op需要非零值的平均值。需要解释你的答案是什么。仅仅发布代码并不一定有帮助。谢谢你的回答。我想问你,这在执行时间上是否很重要?还是有更快的方法?@msalem看起来效率很高。但您可以试试看,解释计划可能需要为两个表上的每个分数规则包含索引。@M问题:我添加了第二个查询,以便每个表只选择一次,如果这样更有效,只需检查实际资源使用情况。如果要删除union,我的版本只有一个联接,但是你还是应该用测试看看哪个版本最快。@JuanCarlosOropeza:太多的联合,我更喜欢联合而不是完全的外部联合-试着也有mysql,postgres和MSSqlSweet!谢谢你,@JuanCarlosOropeza。我不知道雷克斯特的存在。非常感谢。我仍然使用SQLFIDLE,因为它有文本到DDL的功能。然后将DDL移动到rexter。顺便说一句,检查你的网站,请下定决心,3个理由从git移动到svn,3个理由从svn移动到git。这个查询似乎非常有效,但是如果其中一个表没有3列score_rule1、score_rule2、score_rule3怎么办?@msalem-我只能回答你问的问题。我怎么知道你在现实生活中的例子还有什么?如果其中一个表没有这3列,你是什么意思?它有什么,只有一个ID为的列?
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
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;
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