PostgreSQL select value and increment at once - sql

I'm looking for a possible solution to the following. I have data stored in a table to keep track of a special increment number the customer wants in the DB. This is a special number they use internally.
What I would like to do is automatically increment this number in the table when I select it. So I don't have the problem of another transaction, from someone else using the system, using the same ID number.
So I want to select the current number and increment it by one at once so I don't have duplicates. How would I go about doing this if it is even possible?

UPDATE the_table
SET the_column = the_column + 1
WHERE qualifier = X
RETURNING the_column;

This ought to do the trick, with the caveat that it will return the new id rather than the old one:
UPDATE foo
SET id=nextval('foo_sequence')
WHERE ...
RETURNING *

Related

Use addition in database SQL

Can I use addition in database?
For example: I have data inside database that is integer. It has a value of 5.
Is there a query that will add another 1 to that? So it will become 6.
Please help me I'm a beginner.
This is the most basic form of an update statement:
update the_table
set the_column = the_column + 1
where the_column = 5;
Note that the above will update all rows where the_colum has the value 5. You most probably want to change the where clause to something different, e.g. by selecting only a single row by using a condition on the primary key column(s) of the table.
Check the manual of your DBMS for details, e.g.: http://www.postgresql.org/docs/current/static/dml-update.html

SQL / DB2 - retrieve value and update/increment simultaniously

I'm connecting to a DB2 database and executing SQL statements.
One example of what is being done is:
select field from library/file
[program code line finishes executing]
[increment value by one]
update library/file set field = 'incremented value'
I have a need to immediately update the value while returning the value. Rather than having to wait for the script to complete, and then run a separate UPDATE statement.
The concept of what I would like to do is this:
select field from library/file; update library/file set field = (Current Value + 1); go;
Please note... this is not the common SQL database most would be familiar with, it is a DB2 database on an IBM i.
Thanks!
Consider using a DB2 SEQUENCE to manage the next available number, if this file is simply intended to have a single row storing your counter. That is what a SEQUENCE is designed to do.
To set it up, use a CREATE SEQUENCE statement.
To increment the value and retrieve, use a SEQUENCE reference expression of the form NEXT VALUE FOR sequence-name. To find out what the most recent value was, use the PREVIOUS VALUE FOR sequence-name. These expressions can be used like a regular any column expression, such as in a SELECT or INSERT statement.
Suppose, for example you want to do this for invoice numbers (and maybe your accounting department doesn't want their first invoice number to be 000001, so we will initialize it higher).
CREATE SEQUENCE InvoiceSeq
as decimal (7,0)
start with 27000; -- for example
You could get a number for a new invoice like this:
SELECT NEXT VALUE FOR InvoiceSeq
INTO :myvar
FROM SYSIBM/SYSDUMMY1;
But what is this SYSIBM/SYSDUMMY1 table? We're not really getting anything from table, so why are we pretending to do so? The SELECT needs a FROM-table clause. But since we don't need one, let's use a VALUES INTO statement.
VALUES NEXT VALUE FOR InvoiceSeq
INTO :myvar;
So that has incremented the counter, and put the value into our variable. You could use that value to INSERT into our InvoiceHeaders and InvoiceDetails tables.
Or, you could increment the counter as you write an InvoiceHeader, then use it again when writing the InvoiceDetails.
INSERT INTO InvoiceHeaders
(InvoiceNbr, Customer, InvoiceDate)
VALUES (NEXT VALUE FOR InvoiceSeq, :custnbr, :invdate);
for each invoice detail
INSERT INTO InvoiceDetails
(InvoiceNbr, InvoiceLine, Reason, Fee)
VALUES (PREVIOUS VALUE FOR InvoiceSeq, :line, :itemtxt, :amt);
The PREVIOUS VALUE is local to the particular job, so there should be no risk of another job getting the same number.
update library/file set field = field + 1;
select field from library/file;
[program code line finishes executing]
[increment value by one]
This handles the problem of another app updating the number between the time you fetch it and the time you update it. Update it and then use it. If two apps try to update simultaneously, one will wait.
A SEQUENCE object is designed exactly for this purpose, but if you are forced to keep this 'next ID' file updated, this is how I'd do it. Follow the link in the comment by #Clockwork-Muse for info on the SEQUENCE object, or try this example from V5R4.
His request is like this:
UPDATE sometable
SET somecounter = somecounter + 10,
:returnvar = somecounter + 10;
Updates and retrieves at the same time.
This is possible in MSSQL, In fact I use it alot there,
but DB2 doesnt seem to have this feature.

How can I increment a database value in SQL?

I'm facing a problem with a voting system specially in the vote up feature.
How can I make something like votes++ in the database without the need to select the last votes in single query?
UPDATE myTable
SET voteCol = voteCol + 1
WHERE id = idOfInterest;

Oracle SQL: How to read-and-increment a field

I'm refactoring the data import procedure for an enterprise application and came across a snippet I'd like to find a better solution. When importing data we have to create a unique entity for each data set and there is a counter in a field to be used to assign this id sequentially. You read the field to get the next free id and increment it afterwards to prepare for the next time.
At the moment this is done in two steps in the original app, written in 'C':
SELECT idnext FROM mytable;
UPDATE mytable SET idnext = idnext + 1;
Obviously there is a race condition here, if multiple processes do the same thing.
Edit: Important corequisite: I can not touch the database/field definition, this rules out a sequence.
We are rewriting in perl, and I'd like to do the same thing, but better. An atomic solution would be nice. Unfortunately my SQL skills are limited, so I'm turning to collective wisdom :-)
In this particular case, a sequence is the right solution as mentioned. But if in some future situation you need to both update something and return a value in the same statement, you can use the RETURNING clause:
UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ?
If the calling code is PL/SQL, replace the ? with a local PL/SQL variable; otherwise you can bind it as an output parameter in your program.
Edit: Since you mentioned Perl, something like this ought to work (untested):
my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?');
my $idnext;
$sth->bind_param_inout(1, \$idnext, 8);
$sth->execute; # now $idnext should contain the value
See DBI.
Why not use a sequence?
Create the sequence one time, using whatever START WITH value you want:
CREATE SEQUENCE mysequence
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
NOCACHE
NOORDER;
Then in your application code at runtime you can use this statement to get the next value:
SELECT mysequence.NEXTVAL
INTO idnext
FROM DUAL;
Update: Using a sequence would be the preferred method, but since you can't change the database then I agree that using RETURNING should work for your situation:
UPDATE mytable
SET idnext = idnext + 1
RETURNING idnext
INTO mylocalvariable;
Use SELECT FOR UPDATE statement. It guarantees mutually exclusive rights to the record :
"SELECT
FOR UPDATE;
A sequence will do the job, have a look at e.g. Oracle sequences

Updating multiple rows with a value calculated from another column

I have a table with a row that looks like this:
(2009123148498429, '...', '...')
The first part, id, is a timestamp followed by a random number. (needed to work with other parts in the system) The data already exists in the table.
I want to create a column, timestamp, and extract just the date (20091231) and update all the rows with the timestamp.
How can I do this for all the rows with SQL? (i.e. update them all with some sort of a function?)
What kind of default value should I assign the column to make sure that future inserts correctly extract the date?
UPDATE - Please read the comments by bobince in the first answered question by Jonathan Sampson on how we got to the answer. This is the final query that worked:
UPDATE table SET rdate=substring(convert(rid,char(20)),1,8);
The problem was that I was using substring as substring( str, 0, 8 ) whereas it should be substring( str, 1, 8 ). I guess we're all used to 0 as the beginning position! More info here on substring
Related to: multiple updates in mysql
SELECT SUBSTRING(colDate,0,8) as 'date'
FROM someTable
Or am I mistaken?
UPDATE someTable
SET newDateField = SUBSTRING(colDate,0,8)
Would likely work too. Untested.
Use a sub-select in your update (untested, and I've been using Firebird for too long, so someone check me here).
UPDATE MyTable AS TUpdate
SET MyNewField = (SELECT SUBSTRING(TSub.MyDateColumn,0,8)
FROM MyTable AS TSub
WHERE TSub.MyID = TUpdate.MyID);
As for future inserts correctly extracting the date, you're going to have to create a trigger on insert to extract the date for that record.
Need to use a subselect.
UPDATE someTable set timestamp = (SELECT SUBSTRING(colData, 0, 8) FROM someOriginalTable);
EDIT lc got me by a few seconds!
UPDATE tbl
SET
newDateField = SUBSTRING(CAST(sourceCol AS varchar), 0, 8)