Как выполнить условное соединение двух таблиц в BigQuery? - PullRequest
1 голос
/ 09 июля 2020

Я хотел бы объединить две таблицы, и если столбцы не совпадают, тогда следует применить другое условие для объединения таблиц. Таблицы должны объединяться на основе двух продуктов и столбцов уровней. Если продукты совпадают, но уровень не совпадает, то порядок соответствия должен быть Низкий> Средний> Высокий. Например, в сценарии 1 таблица 2 должна совпадать с уровнем Med (строка 2) таблицы 1. Если нет уровня «Med», то будет совпадать с уровнем «High». Например, в Сценарии 2 таблица 2 должна соответствовать Высокому уровню (строка 1) таблицы 1. Если продукты не совпадают или уровень NA, тогда Значение должно быть 0.

Вот другой сценарий ios моей проблемы. Таблица 1 является главной таблицей, а таблица 2 может иметь разные сценарии ios.

Таблица 1

ID  Product_1    Product_2    Level    Value
1   C            D            High     10
2   A            B            Med      11
3   A            B            High     12
4   B            C            Med      13
5   B            C            High     9

Другой сценарий ios таблицы 2

Сценарий 1, таблица 2

Product_1    Product_2    Level
A            B            Low

Ожидаемый результат

Product_1    Product_2    Level    Value
A            B            Med      11

Сценарий 2, таблица 2

Product_1    Product_2    Level
C            D            Low

Ожидаемый результат

Product_1    Product_2    Level    Value
C            D            High      10

Сценарий 3, таблица 2

Product_1    Product_2    Level
A            B            Med

Ожидаемый результат

Product_1    Product_2    Level    Value
A            B            Med      11

Сценарий 4, Таблица 2

Product_1    Product_2    Level
M            N            High

Ожидаемый результат

Product_1    Product_2    Level    Value
M            N            High      0

Сценарий 5, Таблица 2

Product_1    Product_2    Level
A            B            NA

Ожидаемый результат

Product_1    Product_2    Level    Value
A            B            NA       0

Код, который я пробовал, в основном совпадает, если нет, верните «0»

WITH `project.dataset.Table1` AS (
 SELECT 1 ID, 'C' Product_1, 'D' Product_2, 'High' Level, 10 Value UNION ALL
 SELECT 2, 'A', 'B', 'Med', 11 UNION ALL
 SELECT 3, 'A', 'B', 'High', 12 UNION ALL
 SELECT 4, 'B', 'C', 'Med', 13 UNION ALL
 SELECT 5, 'B', 'C', 'High', 9 
),

`project.dataset.Table2` AS (
 SELECT 2 ID, 'A' Product_1, 'B' Product_2, 'Low' Level 
 ),
 
-- The Above table idea is taken from Mikhail's solution

get_values as (
select 
     t1.ID
    ,t2.Product_1
    ,t2.Product_2
    ,t2.Level      
    ,t1.Value
    
FROM `project.dataset.Table1` AS t1
join `project.dataset.Table2` t2 using(Product_1,Product_2,Level)
)

select t2.ID
    ,t2.Product_1
    ,t2.Product_2
    ,t2.Level
    ,IFNULL(Value, 0) as Value

from `project.dataset.Table2` t2
left join get_values gv on t2.ID = gv.ID

Спасибо

Ответы [ 2 ]

2 голосов
/ 10 июля 2020

Ниже приведено для BigQuery Standard SQL

#standardSQL
SELECT Scenario, Product_1, Product_2, candidates.Level, candidates.Value 
FROM (
  SELECT Scenario, Product_1, Product_2, t2.Level, 
    ARRAY_AGG(
      STRUCT(IF(t2.Level = 'NA', 'NA', IFNULL(t1.Level, t2.Level)) AS Level, IF(Value IS NULL OR t2.Level = 'NA', 0, Value) AS Value)
      ORDER BY CASE t2.Level
        WHEN 'Low' THEN CASE t1.Level WHEN 'Low' THEN 1 WHEN 'Med' THEN 2 WHEN 'High' THEN 3 END
        WHEN 'Med' THEN CASE t1.Level WHEN 'Low' THEN 77 WHEN 'Med' THEN 1 WHEN 'High' THEN 2 END
        WHEN 'High' THEN CASE t1.Level WHEN 'Low' THEN 77 WHEN 'Med' THEN 66 WHEN 'High' THEN 1 END
        ELSE 0
      END      
    )[OFFSET(0)] candidates
  FROM `project.dataset.table2` t2
  LEFT JOIN `project.dataset.table1` t1
  USING(Product_1, Product_2)
  GROUP BY Scenario, Product_1, Product_2, Level  
)  

Если применить к образцу данных из вашего вопроса, как в примере ниже

#standardSQL
WITH `project.dataset.table1` AS (
  SELECT 'C' Product_1, 'D' Product_2, 'High' Level, 10 Value UNION ALL
  SELECT 'A', 'B', 'Med', 11 UNION ALL
  SELECT 'A', 'B', 'High', 12 UNION ALL
  SELECT 'B', 'C', 'Med', 13 UNION ALL
  SELECT 'B', 'C', 'High', 9 
),`project.dataset.table2` AS (
  SELECT 1 Scenario, 'A' Product_1, 'B' Product_2, 'Low' Level UNION ALL
  SELECT 2, 'C', 'D', 'Low' UNION ALL
  SELECT 3, 'A', 'B', 'Med' UNION ALL
  SELECT 4, 'M', 'N', 'High' UNION ALL
  SELECT 5, 'A', 'B', 'NA' 
)
SELECT Scenario, Product_1, Product_2, candidates.Level, candidates.Value 
FROM (
  SELECT Scenario, Product_1, Product_2, t2.Level, 
    ARRAY_AGG(
      STRUCT(IF(t2.Level = 'NA', 'NA', IFNULL(t1.Level, t2.Level)) AS Level, IF(Value IS NULL OR t2.Level = 'NA', 0, Value) AS Value)
      ORDER BY CASE t2.Level
        WHEN 'Low' THEN CASE t1.Level WHEN 'Low' THEN 1 WHEN 'Med' THEN 2 WHEN 'High' THEN 3 END
        WHEN 'Med' THEN CASE t1.Level WHEN 'Low' THEN 77 WHEN 'Med' THEN 1 WHEN 'High' THEN 2 END
        WHEN 'High' THEN CASE t1.Level WHEN 'Low' THEN 77 WHEN 'Med' THEN 66 WHEN 'High' THEN 1 END
        ELSE 0
      END      
    )[OFFSET(0)] candidates
  FROM `project.dataset.table2` t2
  LEFT JOIN `project.dataset.table1` t1
  USING(Product_1, Product_2)
  GROUP BY Scenario, Product_1, Product_2, Level  
)

, результат будет

Row Scenario    Product_1   Product_2   Level   Value    
1   1           A           B           Med     11   
2   2           C           D           High    10   
3   3           A           B           Med     11   
4   4           M           N           High    0    
5   5           A           B           NA      0      

Я думаю, что выше в основном дает вам то, что вам нужно, но может потребоваться некоторая настройка, которую, я надеюсь, вы сможете сделать

1 голос
/ 10 июля 2020

В основном я пытался решить указанную выше проблему с помощью временных таблиц.

1. ( sr c) Мы назначаем оценку каждому уровню, который поможет в получении минимальный уровень, доступный в таблице1, в случае отсутствия такого же уровня. Также мы используем полное внешнее соединение, которое поможет найти продукты, отсутствующие в table1 2. ( final ) Эта таблица предоставит нам все продукты, в которых продукт, а также их уровень совпадают между двумя таблицами. 3. ( min_score ) Он даст минимальный балл, доступный для каждого набора product_1 и product_2

with src as
(
 select t1.product1 as t1p1, t1.product_2 as t1p2, t2.product_1 as t2p1, t2.product_2 as t2p2, t1.level as t1_level, t2.level as t2_level,case when t1.level='Low' then 1 
  when t1.level='Med' then 2
  when t1.level='High' then 3
  end as level_score from table1 t1 full outer join table2 t2 on(t1.product_1=t2.product_1 and t1.product_2=t2.product_2)
),
final as
(select t1p1,t1p2,t2p1,t2p2,case when t1_level=t2_level then t1_level else
 '#NA#' as level from src join table1 on(product_1=t1p1 and product2=t1p2) where t1p1 is not null and t1p2 is not null
),
min_score as
(
select t1p1,t1p2,min(level_score) as level_score from src group by t1p1,t1p2 
)
SELECT t2p1,t2p2,t2_level,0 as value FROM src WHERE (t1p1 IS NULL AND t1p2 IS NULL) OR (t2_level='NA')
UNION ALL
SELECT t1p1,t1p2,t1_level,value from final f join table1 tab1 on ( t1p1=product_1 and t1p2=product2 and t1_level=level) where level !='#NA#'
UNION ALL
SELECT t1p1,t2p2, CASE WHEN level_score=1 then 'Low' WHEN level_score=2 THEN 'Med' ELSE 'High' END as final_level,value   from final f join table1 on(product_1=t1p1 and product2=t1p2) where f.level='#NA#' and table1.level= final_level
 ;

Я использовал UNION ALL, так как он будет включать каждую строку (также дублируется, если есть ). Результатом 3 запросов выбора будет-

  1. Первый запрос выбора выдаст все продукты со значением = 0, т.е. либо продукт отсутствует в таблице 1, либо его уровень = NA в таблице 2 (сценарий 4, сценарий 5)
  2. Второй запрос предоставит все продукты вместе с их стоимостью, где продукты и их уровень существуют в обеих таблицах (Сценарий 3)
  3. Он даст мне значение, где у нас есть продукты в обеих таблицы, но их уровень не совпадает. Для этого я выяснил минимальный уровень, присутствующий в таблице 1 для этой комбинации product_1 и product_2, а затем получил значение, сравнивая уровни.
...