2016-09-14 11 views
1

私はPostgreSQLを使っています。私は2つのテーブルを持っています。この問題のために、meには複数のIDがあります。送信されたメッセージを持つ最初のテーブルTable1情報:PostgreSQLの同様の列のマージ

me | friends | messages_sent 
---------------------------- 
0  1   10 
0  2    7 
0  3    7   
0  4    6 
1  1    5 
1  2   12 
... 

Table2取引メッセージでは、受信:

を:私は(ただし、重要な友人のためではない)のようなテーブルを取得できますか

me | friends | messages_received 
---------------------------- 
0  4   17 
0  2    7 
0  1    9   
0  3    0 
... 

me | friends | messages_total 
    ---------------------------- 
    0  1   19 
    0  2   14 
    0  3    7   
    0  4   23 
    ... 

私がかなり困惑している部分は、両方の表にmeで参加している間に、友人の値を追加してeの値はme ...考えですか?

+2

PostgreSQLを使用している場合は、MySQLタグを使用しないでください。 – Barmar

答えて

1

あなたは、単に二つのテーブルの和集合を生成し、そのメッセージは、集計関数でカウント追加mefriendsのグループの組み合わせにGROUP BYを使用することができます。

SELECT me, friends, sum(count) AS messages_total 
FROM (
    SELECT me, friends, messages_sent AS count FROM Table1 
    UNION ALL 
    SELECT me, friends, messages_received FROM Table2 
) AS t 
GROUP BY me, friends; 

編集:私は約ました私の答えを編集して、パトリックの答えをより良いものとして推薦するノートを追加するが、私は単純なベンチマークを実行するのが楽しいと決めた。だから我々は次のセットアップ(各テーブルに100万行)がある場合:次に、第一の溶液

CREATE TABLE table1 (
    me integer not null, 
    friends integer not null, 
    messages_sent integer not null 
); 
CREATE TABLE table2 (
    me integer not null, 
    friends integer not null, 
    messages_received integer not null 
); 
INSERT INTO table1 SELECT n1, n2, floor(random()*10)::integer FROM generate_series(1, 1000) t1(n1), generate_series(1, 1000) t2(n2); 
INSERT INTO table2 SELECT n1, n2, floor(random()*10)::integer FROM generate_series(1, 1000) t1(n1), generate_series(1, 1000) t2(n2); 
CREATE INDEX ON table1(me, friends); 
CREATE INDEX ON table2(me, friends); 
ANALYZE; 

$ EXPLAIN ANALYZE 
     SELECT me, friends, sum(count) AS messages_total 
     FROM (
      SELECT me, friends, messages_sent AS count FROM Table1 
      UNION ALL 
      SELECT me, friends, messages_received FROM Table2 
    ) AS t 
     GROUP BY me, friends; 
                  QUERY PLAN               
------------------------------------------------------------------------------------------------------------------------------ 
HashAggregate (cost=45812.00..46212.00 rows=40000 width=12) (actual time=1201.602..1499.285 rows=1000000 loops=1) 
    Group Key: table1.me, table1.friends 
    -> Append (cost=0.00..30812.00 rows=2000000 width=12) (actual time=0.022..299.260 rows=2000000 loops=1) 
     -> Seq Scan on table1 (cost=0.00..15406.00 rows=1000000 width=12) (actual time=0.020..91.357 rows=1000000 loops=1) 
     -> Seq Scan on table2 (cost=0.00..15406.00 rows=1000000 width=12) (actual time=0.004..77.672 rows=1000000 loops=1) 
Planning time: 0.255 ms 
Execution time: 1529.642 ms 

そして、第二の溶液:だから驚くほど

$ EXPLAIN ANALYZE 
    SELECT me, friends, 
      coalesce(messages_sent, 0) + coalesce(messages_received, 0) AS messages_total 
    FROM Table1 
    FULL JOIN Table2 USING (me, friends) 
    ORDER BY me; 
                    QUERY PLAN                   
------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Sort (cost=219582.13..222082.13 rows=1000000 width=24) (actual time=1501.873..1583.915 rows=1000000 loops=1) 
    Sort Key: (COALESCE(table1.me, table2.me)) 
    Sort Method: external sort Disk: 21512kB 
    -> Merge Full Join (cost=0.85..99414.29 rows=1000000 width=24) (actual time=0.074..912.598 rows=1000000 loops=1) 
     Merge Cond: ((table1.me = table2.me) AND (table1.friends = table2.friends)) 
     -> Index Scan using table1_me_friends_idx on table1 (cost=0.42..38483.49 rows=1000000 width=12) (actual time=0.039..165.772 rows=1000000 loops=1) 
     -> Index Scan using table2_me_friends_idx on table2 (cost=0.42..38483.49 rows=1000000 width=12) (actual time=0.018..194.177 rows=1000000 loops=1) 
Planning time: 1.091 ms 
Execution time: 1615.011 ms 

を、 FULL JOINのソリューションは、インデックスを利用することはできますが、少し悪化します。私はこれが完全な結合と関係していると思います。他のタイプの参加については、はるかに良いでしょう。

+1

SQLには、通常何かを行い、同じ結果を達成するいくつかの方法があります。いくつかの良い、多くの悪い。この答えは第2のカテゴリーの1つです。 – Patrick

1

フィールドmefriendsの両方を使用して2つのテーブルを結合し、受信したメッセージを単純に追加して送信する必要があります。 FULL JOINを使用すると、私が送信しているが友人から受信していないなど、すべての状況が確実に保持されます。

SELECT me, friends, 
     coalesce(messages_sent, 0) + coalesce(messages_received, 0) AS messages_total 
FROM Table1 
FULL JOIN Table2 USING (me, friends) 
ORDER BY me; 
+0

私はあなたが最初のまたは2番目のクエリに特定の組み合わせに対して結果がない場合、結果の合計がnullにならない場合、 にCOALESCE(messages_sent、0)+ COALESCE(messages_received、0) にmessages_sent + messages_receivedを変更できると思います。 –

関連する問題