2016-09-26 11 views
2

Apache Hiveでは、左のデータからすべてのデータを保持し、可能な場合は右の表からデータを追加するために左結合したいテーブルが必要です。 これは2つのフィールド(material_idとlocation_id)に基づいているため、2つの結合を使用します。 これは、2つの伝統的な左で正常に動作しますが、加入:Hive/SQL - フォールバック付きの左結合

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データベースは2つのだけ異なる値が含まれているため、1と2

私たちは今、「いいえがある場合はその要件を持っていると言いますこれは、material_idのみが結合可能であり、bテーブルのlocation_idの結合にmaterial_idとlocation_id(例えばmaterial_id = 100とlocation_id = 1)の正しい組み合わせがないことを意味します。 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:サブクエリONに動作しないhere存在等を述べたようにここ

は、いくつかのサンプルデータです。

+0

サンプルデータを表示する必要があります。 – Andrew

+0

ありがとうAndrew、わかりやすくするためにいくつかのサンプルデータを追加しました。 – alpcoder

答えて

0

解決策は、a.location_id = b.location_idを付けずに左に参加し、すべての行に優先順位を付けます。 row_numberでフィルタリングします。下のコードでは、結合するすべてのmaterial_idが結合されるため、結合が最初に行を複写します。row_number()関数は、a.location_id = b.location_idと2から行への1を割り当てます。a.location_id <> b.location_idが存在する場合はと1が存在します。 b.location_idがrow_number()関数のorder byに追加されているため、正確な一致がない場合は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

多分これは将来的に誰かのために有用である:

我々はまた、別のアプローチを思い付きました。

まず、すべての(!)の場所のmaterial_idに基づいてテーブルbからの平均を計算する別のテーブルを作成します。

c1 - material_idとlocation_idが一致する値(表aと表bの左結合の結果)。完全一致がない場合、この列はnullです。

C2 - このmaterial_idため、我々は平均値(フォールバック)から番号を書き込むテーブルのテーブルからの値(場所に関係なく)

C3 - 我々はcase文を使用して、「実際値」欄列1がNULLの場合(材料と位置の完全一致がない場合)、さらに計算のために列2の値(材料の他のすべての場所の平均)を使用するかどうかを決定する。

+0

THEN 1 ELSE 2 - これらはロケーションIDではありません。これは、ROW_NUMBER()のORDERが行をマークするための値です。 1でマークされた行が最初に注文され、2でマークされた行が2番目に注文され、最後のフィルタはrn = 1をフィルタリングします。ハードコードされた列の値はありません。 – leftjoin

+0

あなたは正しいです。 – alpcoder