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

发布于 2024-10-10 02:48:58 字数 2317 浏览 1 评论 0原文

通过一些模糊的错误(可能在我这边),在年份的变化中,我的表中得到了值“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 ?请问我该如何解决我的问题?

谢谢你! Alex

更新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-52 可能是 2011 年初的正确值。

through some obscure error (probably on my side) over the change of the year I've got values "2011-52" in my table (listing virtual money won by players in a week), which actually belong under "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

To fix that I would like to add the value (63) from the row with the yw='2011-52' to the value (20) of the row with the yw='2011-01' and then drop the former row, for each id in the table.

So I am trying (using 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

this is probably because I need to specify the id too inside the round brackets of the subquery? How can I fix my query please?

Thank you! Alex

UPDATE 2:

I've also tried:

# 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

and

# 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...

and:

# 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

And my table definition is:

# \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)

And of course I have thousands of rows with different id's or I'd just fix 1 value by hand and wouldn't ask here a question at Stackoverflow.

And I don't agree with the comment, that 2011-52 could be a correct value at the beginning of the year 2011.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜血缘 2024-10-17 02:48:58

您需要确保子查询恰好返回一行(如错误消息所示)。您的示例数据没有显示这一点,但显然您的表格中有不止一行带有 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';

You need to make sure that the subquery returns exactly one row (as the error message suggests). Your sample data doesn't show this, but apparently there is more than one row with yw='2011-01' in your table.

If the id column is the primary key (or part of it), then yes adding that to the inner select will rectify this problem.

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';
萌能量女王 2024-10-17 02:48:58

嗯,这个 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 开始。 2011 年 1 月 1 日02/01/2011 确实是第 52 周!

Well, this 52 is maybe not really an error. The first week of this 201 year is really numbered 52 in ISO year. Sometimes it's 0, sometimes it's 52. http://en.wikipedia.org/wiki/ISO_week_date.

So maybe you do not want the ISO number of the week, as it can be a problem when doing order by queries, maybe. Or try to change 2011-52 to 2010-52.

And do not merge 2011-52 and 2011-01, 2011-01 start on 03/01/2011. 01/01/2011 & 02/01/2011 are really in week 52 !

何以笙箫默 2024-10-17 02:48:58

一种可能性是使用聚合并执行类似的操作:

  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';

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

One of the possibilities would be to use an aggregate and do something like:

  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';

But to say the truth, I would use a date data type for the yw field and set a constraint date_trunc('month', yw)::date = yw to ensure the date in yw is only the first day of the month.

月隐月明月朦胧 2024-10-17 02:48:58

我最终做了:

# 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 - 从 [电子邮件受保护] 邮件列表

I've ended up doing:

# 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

And I should have used IYYY-IW instead of YYYY-IW in the 1st place - got both hints from [email protected] mailing list

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文