UPDATE with ORDER BY

后端 未结 6 2325
Happy的楠姐
Happy的楠姐 2020-12-11 01:30

Need to "tie" UPDATE with ORDER BY. I\'m trying to use cursors, but get the error:

cursor "cursupd"         


        
6条回答
  •  渐次进展
    2020-12-11 02:26

    UPDATE with ORDER BY

    As to the question raised ion the title: There is no ORDER BY in an SQL UPDATE command. Postgres updates rows in arbitrary order. But you have (limited) options to decide whether constraints are checked after each row, after each statement or at the end of the transaction. You can avoid duplicate key violations for intermediate states with a DEFERRABLE constraint.

    I am quoting what we worked out under this question:

    • Constraint defined DEFERRABLE INITIALLY IMMEDIATE is still DEFERRED?

    • NOT DEFERRED constraints are checked after each row.

    • DEFERRABLE constraints set to IMMEDIATE (INITIALLY IMMEDIATE or via SET CONSTRAINTS) are checked after each statement.

    There are limitations, though. Foreign key constraints require non-deferrable constraints on the target column(s).

    The referenced columns must be the columns of a non-deferrable unique or primary key constraint in the referenced table.

    Workaround

    Updated after question update.
    Assuming "sequence" is never negative in normal operation, you can avoid unique errors like this:

    UPDATE tbl SET "sequence" = ("sequence" + 1) * -1
    WHERE  "CableLine" = 2;
    
    UPDATE tbl SET "sequence" = "sequence" * -1
    WHERE  "CableLine" = 2
    AND    "sequence" < 0;
    

    With a non-deferrable constraint (default), you have to run two separate commands to make this work. Run the commands in quick succession to avoid concurrency issues. The solution is obviously not fit for heavy concurrent load.

    Aside:
    It's OK to skip the key word AS for table aliases, but it's discouraged to do the same for column aliases.

    I'd advice not to use SQL key words as identifiers, even though that's allowed.

    Avoid the problem

    On a bigger scale or for databases with heavy concurrent load, it's wiser to use a serial column for relative ordering of rows. You can generate numbers starting with 1 and no gaps with the window function row_number() in a view or query. Consider this related answer:

    • Is it possible to use a PG sequence on a per record label?

提交回复
热议问题