2016-08-15 10 views
1

私は2つのテーブルtableを持っていますが、構造は同じですが、異なるスキーマ(スキーマAおよびB)に属しています。問題の行はすべてA.tableに表示されますが、B.tableに表示される場合と表示されない場合があります。 B.tableは、基本的にはA.tableのデフォルトの上書きです。これは素晴らしい作品COALESCEフィールドのソースを決定します

SELECT COALESCE(B.id, A.id) as id, 
     COALESCE(B.foo, A.foo) as foo, 
     COALESCE(B.bar, A.bar) as bar 
FROM A.table LEFT JOIN B.table ON (A.id = B.id) 
WHERE A.id in (1, 2, 3) 

、私はまた、データのソースを追加したい:そのような私のクエリとして

は次のように、各フィールドにCOALESCEを使用しています。上記の例では、がB.tableに存在するものの、1または3は存在しないと仮定して、Aは1と3のソース、Bは2のソースです。

したがって、データは次のようになります私は本当に元の値が限り私はB.

からAを区別できるように私は(ないロングショットで)何pgsqlでの専門家ではありませんが、私が持っているもの気にしない、次の

+---------------------------------+ 
| id | foo | bar | source | 
+---------------------------------+ 
| 1 | a | b |  A | 
| 2 | c | d |  B | 
| 3 | e | f |  A | 
+---------------------------------+ 

EXISTSとサブクエリでうんざりしていたが、今まで運がなかった。 (A.tableからの)デフォルト値を示すレコードとして

答えて

2

はB.idのためのNULLを持って、あなたが必要とするすべてはあなたのクエリにこの列仕様を追加することです:

CASE WHEN B.id IS NULL THEN 'A' ELSE 'B' END AS Source 
+0

美しいです。シンプルだけど、私を逃れました。ありがとう。 – sberry

+0

単純な 'COALESCE'式で' B.foo'がNULL(除外されていない)であれば、 'B.id IS NOT NULL'でも' foo'のソースは 'A'でも構いません。 –

1

USING句は、クエリを簡素化しますあなたが持っている:

SELECT id 
    , COALESCE(B.foo, A.foo) AS foo 
    , COALESCE(B.bar, A.bar) AS bar 
    , CASE WHEN b.id IS NULL THEN 'A' ELSE 'B' END AS source -- like @Terje provided 
FROM a 
LEFT JOIN b USING (id) 
WHERE a.id IN (1, 2, 3);

しかし、一般的に、この代替クエリはより良いサービスを提供する必要があります

SELECT x.* -- or list columns of your choice 
FROM (VALUES (1), (2), (3)) t (id) 
    , LATERAL (
    SELECT *, 'B' AS source FROM b WHERE id = t.id 
    UNION ALL 
    SELECT *, 'A'   FROM a WHERE id = t.id 
    LIMIT 1 
    ) x 
ORDER BY x.id; 

利点:

  • あなたは結果に追加する列ごとに別のCOALESCE構造を追加する必要はありません。
  • abの任意の数の列に対して同じクエリが機能します。
  • 列名が同一でない場合でもクエリが機能します。列の番号とデータ型のみが一致しなければなりません。もちろん は、あなたはいつものようにも、互換性のある列を選択し、リストすることができます

    SELECT * -- or list columns of your choice 
    FROM (VALUES (1), (2), (3)) t (id) 
        , LATERAL (
        SELECT foo, bar, 'B' AS source FROM b WHERE id = t.id 
        UNION ALL 
        SELECT foo2, bar17, 'A'  FROM a WHERE id = t.id 
        LIMIT 1 
        ) x 
    ORDER BY x.id;

    最初SELECTは、名前、データ型と列の数を決定します。

  • bの列が定義されていない場合、このクエリは中断されません。NOT NULL
    COALESCEbidが一致するb.foo IS NULLない行との間の違いを見分けることができません。したがって、結果列が 'B'と表示されても、結果列のソース(idを除く)は 'A'になります。bの関連する列がNULLになることがあります。
    私の代わりの返品すべて値がbの場合、NULL値を含みます。 bの列がNULLの場合は、結果が異なる可能性があります。行動が望ましいあなたの要件に依存します。

いずれクエリがidは、主キー(所与id値ごとので、正確に1または0の行)として定義されていることを前提としています。

関連:

+0

答えと徹底的な内訳ありがとう。テーブルの列数が同じではないので、2番目のテーブルは機能しません。読書に関係なく面白い。 – sberry

+0

@sberry:第2のものもそれのために働く。 LATERALクエリでは 'SELECT * 'を使って構文ショートカットを実行することはできません。私は例といくつかの説明を追加しました。 –

関連する問題