2016-09-26 4 views
2

В Apache Hive У меня есть таблицы, которые я хотел бы оставить слева, сохраняя все данные из левых данных и добавляя данные по возможности из правой таблицы. Для этого я использую два объединения, потому что соединение основано на двух полях (material_id и location_id). Это прекрасно работает с двумя традиционными слева присоединяется:Hive/SQL - Left join with fallback

SELECT 
    a.*, 
    b.* 
FROM a 
INNER JOIN (some more complex select) b 
    ON a.material_id=b.material_id 
    AND a.location_id=b.location_id; 

Для LOCATION_ID база данных содержит только два различных значения, скажем 1 и 2.

Теперь у нас есть требование, что если нет " идеальное совпадение ", это означает, что только соединение material_id может быть объединено, и нет правильной комбинации material_id и location_id (например, material_id = 100 и location_id = 1) для соединения для location_id в b-таблице, соединение должно" по умолчанию "или" возврат "к другому возможному значению location_id, например material_id = 001 и location_id = 2 и наоборот. Это должно быть только для location_id.

Мы уже рассмотрели все возможные ответы и с CASE и т. Д., Но не превалировали. Установка, подобная

... 
ON a.material_id=b.material_id AND a.location_id= 
CASE WHEN a.location_id = b.location_id THEN b.location_id ELSE ...; 

Мы попытались или не смогли понять, как реально работать в языке запросов на улей.

Благодарим за помощь! Может быть, у кого-то есть умная идея.

Вот некоторые примерные данные:

Table a 
| material_id | location_id | other_column_a | 
| 100   | 1   | 45   | 
| 101   | 1   | 45   | 
| 103   | 1   | 45   | 
| 103   | 2   | 45   | 



Table b 
| material_id | location_id | other_column_b | 
| 100   | 1   | 66   | 
| 102   | 1   | 76   | 
| 103   | 2   | 88   | 


Left - Join Table 
| material_id | location_id | other_column_a | other_column_b 
| 100   | 1   | 45   | 66 
| 101   | 1   | 45   | NULL (mat. not in b) 
| 103   | 1   | 45   | DEFAULT TO where location_id=2 (88) 
| 103   | 2   | 45   | 88 

PS: Как указано here существует и т.д. не работает в ON суб-запроса.

+0

Похоже, вам нужно будет показать нам некоторые образцы данных. – Andrew

+0

Спасибо, Андрей, я добавил некоторые примеры данных для ясности. – alpcoder

ответ

0

Решение состоит из левого соединения без a.location_id = b.location_id и номера всех строк в порядке предпочтения. Затем фильтруйте по номеру строки. В приведенном ниже коде объединение будет дублировать строки сначала, потому что все подходящие material_id будут объединены, тогда функция row_number() назначит 1 строкам, где a.location_id = b.location_id и 2 в строки, где a.location_id <> b.location_id, если существуют также строки, где a.location_id = b.location_id и 1, если их не существует. b.location_id добавлен в order by в функцию row_number(), поэтому он будет «предпочитать» строки с нижним b.location_id в случае, если нет точного соответствия. Надеюсь, ты поймал эту идею.

select * from 
(
SELECT 
    a.*, 
    b.*, 
    row_number() over(partition by material_id 
        order by CASE WHEN a.location_id = b.location_id THEN 1 ELSE 2 END, b.location_id) as rn 
FROM a 
LEFT JOIN (some more complex select) b 
    ON a.material_id=b.material_id 
)s 
where rn=1 
; 
+0

Подписанный вами подход действительно сработал, поэтому я отметил его полезным. Однако наше требование теперь изменилось, чтобы местоположение не было жестко запрограммировано. Я опубликую текущее решение. – alpcoder

+0

Не могли бы вы объяснить, что жестко закодировано в этом коде? Значения Location_id не являются жестко запрограммированными и могут быть любыми – leftjoin

+0

Насколько я понимаю, THEN 1 ELSE 2 жестко запрограммирован, как это будет работать с большим количеством мест? НО ДА, ваш ответ - ответ на мой первоначальный вопрос и прекрасно работает. Большое спасибо! – alpcoder

0

Может быть, это полезно для кого-то в будущем:

Мы также пришли с другим подходом.

Сначала мы создаем другую таблицу для вычисления средних значений из таблицы b на основе material_id по всем (!) Местоположениям.

Во-вторых, в таблице соединений мы создаем три столбца: c1 - значение, в котором сопоставляются material_id и location_id (результат из левого соединения таблицы a с таблицей b). Этот столбец является нулевым, если нет идеального соответствия.

c2 - значение из таблицы, где мы пишем число из таблицы средние (запасной вариант) для этого material_id (независимо от местоположения)

c3 - столбец «действительное значение», где мы используем случай заявление чтобы решить, будет ли столб столбца NULL (нет идеального соответствия материала и местоположения), мы используем значение из столбца 2 (среднее по всем другим местоположениям материала) для дальнейших вычислений.

+0

THEN 1 ELSE 2 - это не идентификаторы местоположений. Это просто значения для ORDER в ROW_NUMBER() для маркировки строк. Строки, отмеченные 1, будут упорядочены первыми, строка с пометкой 2 будет заказываться секундой, затем фильтр в конце будет фильтровать rn = 1. Нет никаких значений жестко заданных столбцов. – leftjoin

+0

Вы правы. – alpcoder