2

So, I have the following code that updates a language string table, based on an id, and a language code. If I perform a SELECT using the same from expression, it selects just one row. If I do update, it updates all rows. Where am I going wrong with this?

UPDATE shopmaster.catalog_lang SET shortname='TEST' 
FROM shopmaster.catalog_lang cl LEFT JOIN shopmaster.lang l ON cl.langid=l.langid 
WHERE cl.catalogid=7 AND l.code='fr';

Here's the definition of the two tables:

CREATE TABLE IF NOT EXISTS shopmaster.lang(
    langid SERIAL,
    name TEXT,
    code TEXT,
    active BOOLEAN,
    donotdelete BOOLEAN,
    PRIMARY KEY (langid)


CREATE TABLE IF NOT EXISTS shopmaster.catalog_lang(
    catalogid INT references shopmaster.catalog(catalogid),
    langid INT references shopmaster.lang(langid),
    title TEXT,
    shortname TEXT,
    dirname TEXT,
    PRIMARY KEY (catalogid, langid)
);
whitelined
  • 310
  • 4
  • 13
  • 2
    [Quote from the manual](https://www.postgresql.org/docs/current/static/sql-update.html) "*Note that the target table must not appear in the from_list, unless you intend a self-join*". The SELECT equivalent of what you are doing is `select * from catalog_lang cross join catalog_lang left join lang on ...` –  Aug 24 '18 at 10:49
  • BTW: why the **LEFT** join? (combined with `WHERE ... AND l.code='fr';` – joop Aug 24 '18 at 10:54

1 Answers1

3

Don't repeat the table being updated in the FROM. So:

UPDATE shopmaster.catalog_lang cl
    SET shortname = 'TEST' 
FROM shopmaster.lang l 
WHERE cl.langid = l.langid AND cl.catalogid = 7 AND l.code = 'fr';

In Postgres each reference to the table is separate. Your update is equivalent to this SELECT:

SELECT . . .
FROM shopmaster.catalog_lang CROSS JOIN
     shopmaster.catalog_lang cl LEFT JOIN
     shopmaster.lang l
     ON cl.langid = l.langid 
WHERE cl.catalogid = 7 AND l.code = 'fr';

And this is definitely not what you intend.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786