Исключение записей из таблицы на основе правил из другой таблицы - PullRequest
0 голосов
/ 17 апреля 2020

Я использую Oracle SQL, и у меня есть таблица продуктов с различными атрибутами и объемом продаж для каждого продукта и другая таблица с определенными правилами исключения для различного уровня агрегации. Давайте рассмотрим пример:

Вот наша основная таблица с данными о продажах, по которым мы хотим выполнить некоторые расчеты:

enter image description here

А другая таблица содержит различные правила, которые, как предполагается, исключают определенные строки из таблицы выше:

enter image description here

Когда есть "x", этот столбец должен Не следует учитывать, что наши правила таковы: 1. исключить все строки с ATTR_3 = «нет» 2. исключить все строки с ATTR_1 = «Европа» и ATTR_2 = «закуски» и ATTR_3 = «нет» 3. исключить все строки с ATTR_1 = 'Африка'

И исходя из этого наш конечный результат должен быть таким:

enter image description here

Как этого можно достичь в SQL? Я думал о соединении, но понятия не имею, как обрабатывать разные уровни агрегации для исключений.

Ответы [ 4 ]

1 голос
/ 17 апреля 2020

I думаю ваш ожидаемый результат неверен. Ни одно из правил не исключает 2-й ряд (Европа - закуски - да).

SQL> with
  2  -- sample data
  3  test (product_id, attr_1, attr_2, attr_3) as
  4    (select 81928 , 'Europe', 'beverages', 'yes' from dual union all
  5     select 16534 , 'Europe', 'snacks'   , 'yes' from dual union all
  6     select 56468 , 'USA'   , 'snacks'   , 'no'  from dual union all
  7     select 129921, 'Africa', 'drinks'   , 'yes' from dual union all
  8     select 123021, 'Africa', 'snacks'   , 'yes' from dual union all
  9     select 165132, 'USA'   , 'drinks'   , 'yes' from dual
 10    ),
 11  rules (attr_1, attr_2, attr_3) as
 12    (select 'x'     , 'x'     , 'no' from dual union all
 13     select 'Europe', 'snacks', 'no' from dual union all
 14     select 'Africa', 'x'     , 'x'  from dual
 15    )
 16  -- query you need
 17  select t.*
 18  from test t
 19  where (t.attr_1, t.attr_2, t.attr_3) not in
 20    (select
 21       decode(r.attr_1, 'x', t.attr_1, r.attr_1),
 22       decode(r.attr_2, 'x', t.attr_2, r.attr_2),
 23       decode(r.attr_3, 'x', t.attr_3, r.attr_3)
 24     from rules r
 25    );

PRODUCT_ID ATTR_1 ATTR_2    ATT
---------- ------ --------- ---
     81928 Europe beverages yes
     16534 Europe snacks    yes
    165132 USA    drinks    yes

SQL>
0 голосов
/ 17 апреля 2020

Я бы сделал это с тремя различными not exists:

select p.*
from product p
where not exists (select 1
                  from rules r
                  where r.attr_1 = p.attr_1 and r.attr_1 <> 'x'
                 ) and
      not exists (select 1
                  from rules r
                  where r.attr_2 = p.attr_2 and r.attr_2 <> 'x'
                 ) and
      not exists (select 1
                  from rules r
                  where r.attr_3 = p.attr_3 and r.attr_3 <> 'x'
                 ) ;

В частности, это может использовать преимущества индексов на (attr_1), (attri_2) и (attr_3) - что вполне удобно, если у вас умеренное количество правил.

0 голосов
/ 17 апреля 2020

Вы можете использовать соединение, используя оператор CASE .. WHEN следующим образом:

SELECT P.* 
  FROM PRODUCT P
  JOIN RULESS R ON 
        (R.ATTR_1 ='X' OR P.ATTR_1 <> R.ATTR_1)
        AND (R.ATTR_2 ='X' OR P.ATTR_2 <> R.ATTR_2) 
        AND (R.ATTR_3 ='X' OR P.ATTR_3 <> R.ATTR_3) 
0 голосов
/ 17 апреля 2020

Вы можете использовать NOT EXISTS

SELECT *
  FROM sales s
 WHERE NOT EXISTS ( 
                   SELECT 0
                     FROM attributes a
                    WHERE ( ( a.attr_1 = s.attr_1 AND a.attr_1 IS NOT NULL ) 
                       OR     a.attr_1 IS NULL )
                      AND ( ( a.attr_2 = s.attr_2 AND a.attr_2 IS NOT NULL ) 
                       OR     a.attr_2 IS NULL )
                      AND ( ( a.attr_3 = s.attr_3 AND a.attr_3 IS NOT NULL ) 
                       OR     a.attr_3 IS NULL )
                  )

, где я рассматривал значения x в таблице attributes как NULL. Если у вас действительно есть x символов, тогда вы можете использовать :

SELECT *
  FROM sales s
 WHERE NOT EXISTS ( 
                   SELECT 0
                     FROM attributes a
                    WHERE ( ( NVL(a.attr_1,'x') = s.attr_1 AND NVL(a.attr_1,'x')!='x' ) 
                       OR     NVL(a.attr_1,'x')='x' )
                      AND ( ( NVL(a.attr_2,'x') = s.attr_2 AND NVL(a.attr_2,'x')!='x' ) 
                       OR     NVL(a.attr_2,'x')='x' )
                      AND ( ( NVL(a.attr_3,'x') = s.attr_3 AND NVL(a.attr_3,'x')!='x' ) 
                       OR     NVL(a.attr_3,'x')='x' )
                  )

.

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...