2016-08-19 4 views
-1

Вот конфигурация я начиная с:соединить 2 таблицы в Oracle SQL

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

Ну, тогда вам не нужно использовать функцию avg() f где-нибудь? Дизайн вашего стола выглядит ошибочным. Зачем вам нужны две таблицы, которые хранят одно и то же? Добавьте столбец набора правил в одну таблицу. – OldProgrammer

+1

Вы просто игнорируете нули при вычислении среднего? – dnoeth

+0

Да, я просто игнорирую нули, а для функции avg() это не похоже на трюк – dark

ответ

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.

+0

Благодарим вас за ответ. Я хотел бы спросить вас, является ли это «тяжелым» во время выполнения? или есть более быстрый способ? – dark

+0

@msalem Выглядит очень эффективно. Но вы можете попробовать и посмотреть, что 'EXPLAIN PLAN', вероятно, потребуется включить индекс для каждого' score_rule' на обе таблицы. –

+0

@msalem: я добавил второй запрос для выбора только один раз для таблицы, просто проверьте фактическое использование ресурсов, если это более эффективно. – dnoeth

-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 
+0

close, но op нужно avg ненулевых значений. –

+1

нужно объяснить, что ваш ответ. Просто отправить код не обязательно полезно. –

0

Вот пример с PostgreSQL, который вы могли бы адаптировать с Oracle (извините, Oracle SQLFiddle не сотрудничает). Благодаря предложению Хуана Карлоса Оропеза, тем ниже код работает на 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 

SQLFiddle с PostgreSQL версии здесь: http://sqlfiddle.com/#!15/24e3f/1.

Этот пример объединяет идентификатор из обеих таблиц, используя union. Таким образом, один и тот же идентификатор в обоих ruleset1 и ruleset2 появляется только один раз в результате. r - это псевдоним, присвоенный этой сгенерированной таблице.

Все id s затем левые, соединенные обеими таблицами. Во время процесса суммирования возможно, что значения NULL, полученные в результате левого соединения, могут повлиять на результат. Таким образом, NULL объединяются в нуль в математике.

+1

попробуйте [** rexter **] (http://rextester.com/l/oracle_online_compiler) также есть mysql, postgres и MSSql –

+0

Sweet! Спасибо, @JuanCarlosOropeza. Я не знал, что существует rexter. Очень признателен. – zedfoxus

+0

Я все еще использую 'sqlFiddle', потому что имеет функцию« Text to DDL ». Но затем переместите DDL на rexter. btw проверка вашего сайта, PLS составляют ваш разум, 3 причины перейти от git к svn и 3 причины перейти от svn к git. –

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

0

union all ваши две таблиц, UNPIVOT, изменить нули в нуль с nullif, и использовать стандартный 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 
+0

кажется, что этот запрос очень эффективен, но что, если в одной из таблиц нет 3 столбцов (score_rule1, score_rule2, score_rule3)? – dark

+0

@msalem - Я могу ответить только на ваш вопрос. Как я могу узнать, что еще может быть в вашем реальном примере?Что вы имеете в виду, если в одной из таблиц нет трех столбцов? Что у него есть, всего один столбец с идентификатором? – mathguy

Смежные вопросы