2016-09-03 2 views
0

Существует таблица t1, в которой мне нужно заменить id новым значением.PostgreSql: почему это обновление работает некорректно?

Вторая таблица t_changes содержит замены old_id-> new_id. Но когда я делаю ОБНОВЛЕНИЕ, t1 содержит то же новое значение id для всех записей. Что плохого? Такое же обновление работает в T-SQL успешно.

drop table t1; 
drop table t2; 
drop table t_changes; 

create table t1 
(id INT,name text, new_id INT default(0)); 

create table t_changes 
(old_id INT,new_id int) 

insert into t1(id,NAME) 
VALUES (1,'n1'),(2,'n2'),(3,'n3'); 

insert into t_changes(old_id,new_id) 
values(1,11),(2,12),(3,13),(4,13) 

select * from t1; 
select * from t_changes; 

-------!!!! 
update t1 
set new_id = n.new_id 
from t1 t 
inner join t_changes n 
on n.old_id=t.id; 

select * from t1 
------------------------------ 
"id" "name" "new_id" 
----------------- 
"1" "n1" "11" 
"2" "n2" "11" 
"3" "n3" "11" 

ответ

1

Это ваши Postgres update заявление:

update t1 
    set new_id = n.new_id 
    from t1 t inner join 
     t_changes n 
     on n.old_id = t.id; 

Проблема заключается в том, что t1 в update относится к другому t1 в from. Вы намерены, чтобы они были одной и той же ссылкой. Вы можете сделать это так:

update t1 
    set new_id = n.new_id 
    from t_changes n 
    where n.old_id = t.id; 

Ваш синтаксис довольно близко к синтаксису поддерживается некоторыми другими базами данных (например, SQL Server). Тем не менее, для них, вам нужно будет использовать псевдоним таблицы в обновлении:

update t 
    set new_id = n.new_id 
    from t1 t inner join 
     t_changes n 
     on n.old_id = t.id; 
+0

Ok, Thnx. Ты прав. Я переношу бизнес-логику SQL Server в PostgreSql, и это является причиной такой проблемы. Это утверждение работает в T-Sql, но не работает так, как ожидалось в PostgreSql. Мне нужно просмотреть все обновления stmts, как этот. – Oleg

+0

@Oleg: это задокументировано [в руководстве] (https://www.postgresql.org/docs/current/static/sql-update.html#AEN88864): «* Обратите внимание, что целевая таблица не должна отображаться в from_list, если вы не намерены объединиться * * –

+0

@Oleg. , , Ваш запрос не работал бы корректно в SQL Server, потому что 't1' получает псевдоним' t' в предложении 'FROM'. «UPDATE» использует имя таблицы вместо псевдонима (хотя, возможно, ваш фактический запрос не имеет этой проблемы). –

1

Как насчет делать это вместо:

update t1 
set new_id = (SELECT new_id FROM t_changes WHERE old_id=id); 

Обратите внимание, что если для некоторой строки в t1 нет соответствующей строки в t_changes, это изменит t1.new_id к NULL.