【问题标题】:Merge two tables with same column names, add counters合并两个具有相同列名的表,添加计数器
【发布时间】:2011-07-06 22:56:35
【问题描述】:

我有两个具有相同列的表,第一列是名称,第二列是计数。我想合并这些表,以便每个名称与两个表的添加计数一起出现:

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

目前我已经创建了一个非常丑陋的结构来执行它,并且想知道是否有可能以更优雅的方式获得结果。

到目前为止我所拥有的(Table1 是 test1,Table2 是 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;

【问题讨论】:

    标签: sql postgresql merge


    【解决方案1】:
    => 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)
    

    【讨论】:

    • 谢谢,只是想弄清楚“X”是什么?在文档中找不到。
    • X 是一个表别名(谷歌)。在这种情况下,表实际上是由子查询形成的表表达式。 PostgreSQL 和 MySQL(至少)要求命名子查询。该语句可以写成'select X.name,sum(X.cnt) ...'。但是,由于我不使用别名,所以我只是给它一个虚拟名称。
    【解决方案2】:

    这个怎么样,在纯 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 提供 NULL。

    COALESCE 函数返回第一个非 NULL 参数,因此我们使用它来将 NULL 计数“转换”为 0,并从正确的表中选择名称。感谢您提供有关此韦恩的提示!

    祝你好运!

    【讨论】:

    • coalesce 函数是你想的吗?例如,coalesce(t1.name, t2.name)coalesce(t1.count, 0) + coalesce(t2.count, 0)
    • 另外,在 Postgresql 中,您可以将连接条件简单地编写为 USING (name),然后在列列表中简单地引用 nameSELECT name, ... FROM t1 FULL OUTER JOIN t2 USING (name)
    【解决方案3】:

    另一种方法是使用 NATURAL FULL OUTER JOIN 结合 SUM(count) 和 GROUP BY name 语句。下面的 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 列确保 NATURAL FULL OUTER JOIN 为 t1 中的每一行和 t2 中的每一行创建一个单独的行。换句话说,行“name3, 3”和“name4, 4”在中间结果中出现了两次。为了合并这些重复的行并对计数求和,我们可以按名称列对行进行分组并对计数列求和。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-28
      • 1970-01-01
      • 2016-09-04
      • 1970-01-01
      相关资源
      最近更新 更多