2011-03-02 81 views
5

我有兩個具有相同列的表,第一列是名稱,第二列是計數。我想合併這些表,讓每個名字出現在兩個表的增加數:合併具有相同列名的兩個表,添加計數器

Table1:   Table2:   Result Table: 
NAME COUNT  NAME COUNT  NAME COUNT 
name1 1   name3 3   name1 1 
name2 2   name4 4   name2 2 
name3 3   name5 5   name3 6 
name4 4   name6 6   name4 8 
            name5 5 
            name6 6 

正如我已經創建了一個很醜的結構來執行這個時刻,並想知道如果有可能以更優雅的方式獲得結果。

我有什麼至今(表1是測試1和表2中的Test2):

create table test1 (name varchar(40), count integer); 
create table test2 (name varchar(40), count integer); 
create table test3 (name varchar(40), count integer); 
create table test4 (name varchar(40), count integer); 
create table test5 (name varchar(40), count integer); 

insert into test4 (name, count) select * from test1; 
insert into test4 (name, count) select * from test2; 
insert into test3 (name , count) select t1.name, t1.count + t2.count 
from test1 t1 inner join test2 t2 on t1.name = t2.name; 
select merge_db(name, count) from test3; 
insert into test5 (name, count) (select name, max(count) from test4 group by name); 


CREATE FUNCTION merge_db(key varchar(40), data integer) RETURNS VOID AS 
    $$ -- souce: http://stackoverflow.com/questions/1109061/insert-on-duplicate-update-postgresql 
    BEGIN 
     LOOP 
      -- first try to update the key 
      UPDATE test4 SET count = data WHERE name = key; 
      IF found THEN 
       RETURN; 
      END IF;-- not there, so try to insert the key -- if someone else inserts the same key concurrently,  -- we could get a unique-key failure 
      BEGIN 
       INSERT INTO test4(name,count) VALUES (key, data); 
       RETURN; 
      EXCEPTION WHEN unique_violation THEN-- do nothing, and loop to try the UPDATE again 
      END; 
     END LOOP; 
    END; 
    $$ 
    LANGUAGE plpgsql; 

回答

11
=> create table t1 (name text,cnt int); 
=> create table t2 (name text,cnt int); 
=> insert into t1 values ('name1',1), ('name2',2), ('name3',3), ('name4',4); 
=> insert into t2 values ('name3',3), ('name4',4), ('name5',5), ('name6',6); 
=> 

select name,sum(cnt) from 
(select * from t1 
union all 
select * from t2) X 
group by name 
order by 1; 

name | sum 
-------+----- 
name1 | 1 
name2 | 2 
name3 | 6 
name4 | 8 
name5 | 5 
name6 | 6 
(6 rows) 
+1

謝謝,只是想弄清楚「X」是什麼?無法在文檔中找到它。 – evgeni 2011-03-03 19:17:17

+2

X是一個表別名(Google)。在這種情況下,該表實際上是一個由子查詢形成的表表達式。 PostgreSQL和MySQL(至少)要求子查詢被命名。該語句可以寫成'select X.name,sum(X.cnt)...'。但是,由於我不使用別名,我只是給它一個虛擬名稱。 – Reece 2011-03-07 00:05:31

8

這個怎麼樣,在純SQL:

SELECT 
    COALESCE(t1.name, t2.name), 
    COALESCE(t1.count, 0) + COALESCE(t2.count, 0) AS count 
FROM t1 FULL OUTER JOIN t2 ON t1.name=t2.name; 

基本上我們正在做一個完全外部聯接在名稱字段上合併兩個表。棘手的部分是,對於完整的外連接,存在於一個表中但不存在於其他表中的行將出現,但在另一個表中將具有NULL;所以如果t1有「name1」但t2沒有,那麼連接會爲我們提供t2.name和t2.name的空值。

COALESCE函數返回第一個非NULL參數,因此我們用它將NULL計數「轉換」爲0並從正確的表中選擇名稱。感謝這個韋恩的提示!

祝你好運!

+2

合併功能是你在想什麼?例如'coalesce(t1.name,t2.name)','coalesce(t1.count,0)+ coalesce(t2.count,0)'。 – 2011-03-02 02:17:36

+0

是的,就是那個! – 2011-03-02 02:24:11

+5

另外,在Postgresql中,您可以簡單地使用'USING(name)'來編寫連接條件,然後在列表中簡單引用'name':'SELECT name,... FROM t1 FULL OUTER JOIN t2 USING(name) – araqnid 2011-03-02 10:56:48

0

另一種方法是將NATURAL FULL OUTER JOIN與SUM(count)和GROUP BY名稱語句結合使用。以下SQL代碼完全產生所需的結果:

SELECT name, SUM(count) AS count FROM 
    (SELECT 1 AS tableid, * FROM t1) AS table1 
NATURAL FULL OUTER JOIN 
    (SELECT 2 AS tableid, * FROM t2) AS table2 
GROUP BY name ORDER BY name 

人工TABLEID柱確保自然科學FULL OUTER JOIN對於t1每一行和在T2每一列建立單獨的列。換句話說,行「name3,3」和「name4,4」在中間結果中出現兩次。爲了合併這些重複的行並總計計數,我們可以按名稱列對行進行分組並計算總計計數列。

相關問題