PostgreSQL: добавьте значение одной строки в другую и отбросьте первую - PullRequest
0 голосов
/ 03 января 2011

из-за какой-то неясной ошибки (вероятно, с моей стороны) по смене года, в моей таблице есть значения «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

Чтобы исправить это, я хотел бы добавить значение (63) из строки с yw = '2011-52' к значению (20) строки с yw= '2011-01', а затем отбросьте первую строку для каждого идентификатора в таблице.

Итак, я пытаюсь (используя 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)

И, конечно, у меня есть тысячи строк с разными идентификаторами, или я просто исправлю 1 значение вручную и не буду спрашивать здесьвопрос в Stackoverflow.

И я не согласен с комментарием, что 2011-52 гг. может быть правильным значением в начале 2011 г.

Ответы [ 4 ]

1 голос
/ 03 января 2011

Необходимо убедиться, что подзапрос возвращает ровно одну строку (как следует из сообщения об ошибке).Ваш пример данных не показывает этого, но, очевидно, в вашей таблице более одной строки с 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';
0 голосов
/ 03 января 2011

В итоге я сделал:

# 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 на 1-м месте - получил оба совета от pgsql-generalсписок рассылки @ postgresql.org

0 голосов
/ 03 января 2011

Одна из возможностей - использовать агрегат и сделать что-то вроде:

  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 будет только первым днем ​​месяца.

0 голосов
/ 03 января 2011

Ну, это 52, возможно, не совсем ошибка. Первая неделя этого 201-го года действительно насчитывает 52 года ISO. Иногда 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 неделе!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...