PostgreSQL:将一行的值添加到另一行并删除前者

时间:2011-01-03 11:57:35

标签: postgresql

通过一些模糊的错误(可能在我身边)对年度的变化我在我的表中列出了值“2011-52”(列出了一周内玩家赢得的虚拟货币),实际属于“2011” -01" :

# select * from pref_money where id='OK324712148886';
       id       | money |   yw
----------------+-------+---------
 OK324712148886 |   203 | 2010-46
 OK324712148886 |   219 | 2010-49
 OK324712148886 |   115 | 2010-51
 OK324712148886 |    63 | 2011-52
 OK324712148886 |    20 | 2011-01

要解决此问题,我想将yw ='2011-52'的行中的值(63)添加到yw ='2011-01'的行的值(20),然后删除前一行,表中的每个id。

所以我正在尝试(使用PostgreSQL 8.4.6 / CentOS 5.5):

# update pref_money set money=money+
    (select money from pref_money where yw='2011-52') 
    where yw='2011-01';
ERROR:  more than one row returned by a subquery used as an expression

这可能是因为我需要在子查询的圆括号内指定 id ?我该如何解决我的问题?

谢谢!亚历

更新2:

我也试过了:

# update pref_money set money=money+
(select money from pref_money m2 where m2.yw='2011-52' and id=m2.id) 
where yw='2011-01';
ERROR:  more than one row returned by a subquery used as an expression

# update pref_money m1 set m1.money=m1.money+
(select money from pref_money m2 where m2.yw='2011-52' and m1.id=m2.id) 
where m1.yw='2011-01';
ERROR:  column "m1" of relation "pref_money" does not exist
LINE 1: update pref_money m1 set m1.money=m1.money+(select money fro...

# update pref_money as m1 set money=money+
(select coalesce(money,0) from pref_money as m2 
where m1.id=m2.id and m2.yw='2011-52') 
where m1.yw='2011-01';
ERROR:  null value in column "money" violates not-null constraint

我的表定义是:

# \d pref_money
                        Table "public.pref_money"
 Column |         Type          |                Modifiers
--------+-----------------------+-----------------------------------------
 id     | character varying(32) |
 money  | integer               | not null
 yw     | character(7)          | default to_char(now(), 'YYYY-IW'::text)
Indexes:
    "pref_money_yw_index" btree (yw)
Foreign-key constraints:
    "pref_money_id_fkey" FOREIGN KEY (id) REFERENCES pref_users(id)

当然,我有成千上万行具有不同的ID,或者我只是手动修复1个值,并且不会在这里向Stackoverflow提出问题。

我不同意这一评论,即2011年至2011年可能是2011年年初的正确值。

4 个答案:

答案 0 :(得分:1)

您需要确保子查询只返回一行(如错误消息所示)。您的示例数据未显示此信息,但显然您的表中有 yw ='2011-01'的多行。

如果id列是主键(或其中的一部分),则将其添加到内部选择将解决此问题。

update pref_money 
  set money=money +
       (select money 
          from pref_money m2 
         where m2.yw = '2011-52'
           and m2.id = pref_money.id)
where yw='2011-01';

答案 1 :(得分:0)

嗯,这52可能不是真的错误。这个201年的第一周在ISO年份确实达到了52个。有时它是0,有时它是52. http://en.wikipedia.org/wiki/ISO_week_date

所以也许你不想要一周的ISO编号,因为在查询订单时可能会出现问题。或者尝试将2011-52更改为2010-52。

不要合并2011-52和2011-01,2011-01在03/01/2011开始。 01/01/2011& 02/01/2011真的是在第52周!

答案 2 :(得分:0)

其中一种可能性是使用聚合并执行以下操作:

  update pref_money as pm 
     set money = money+money_delta
    from ( select id, sum(money) as money_delta 
             from pref_money as pmt 
            where yw > '2011-01' -- here you should include only the records, that are really corrupted
                                 -- for the example of the data from you, text > should work
            group by id) as pmd
   where pm.id = pmd.id;
     and pm.yw = '2010-01';

但说实话,我会为date字段使用yw数据类型,并设置约束date_trunc('month', yw)::date = yw以确保yw中的日期仅为这个月的第一天。

答案 3 :(得分:0)

我最终做了:

# update pref_money as m1 set money=money+
      coalesce((select money from pref_money as m2 
      where m1.id=m2.id and m2.yw='2011-52'),0) 
      where m1.yw='2010-52';
UPDATE 2081

# delete from pref_money where yw='2011-52';
DELETE 1223

我应该首先使用 IYYY-IW 代替YYYY-IW - 从pgsql-general@postgresql.org邮件列表中获得两个提示